Background
We are implementing this algorithm in F#.
Here is a little bit more information from Topor (1982) about the notation that the algorithm uses:
Formally, a 't list is either null (denoted nil) or has a hd (which is a 't) and a tl (which is a 't list)... If x is a list, we test whether it is null by writing null x... We create a new list, adding the element a at the front of an existing list x, by writing a:x... We denote the unit list containing the element a by list(a)... list(x) = x:nil.
Question
What we're wondering is how in F# to express those nil, null, and list(nil) values. For instance, should we be using the Option type, an empty list, or something else?
What We Have Tried
let rec kpermute k (xs: 't list) =
let rec mapPerm k xs ys =
match ys with
| [] -> []
| head::tail ->
let kpermuteNext = kpermute (k-1) (removeFirst head xs)
let mapPermNext = mapPerm k xs tail
mapcons head kpermuteNext mapPermNext
match k with
| 0 -> [[]]
| _ when xs.Length < k -> []
| _ -> mapPerm k xs xs
When working with lists, for list(nil) we use [[]] and for nil we use []. While that's fine, there might be a more expressive way to do it. There are also times when we use List.empty<'t list> and List.empty<'t> when the type inference needs more information.
The paper gives you all the answers: nil is []; null x is a test for whether x is the empty list; list(nil) is [[]].
The naïve translation of algorithm B to F# is as follows:
let rec minus a = function
| [] -> failwith "empty list"
| xh :: xt -> if xh = a then xt else xh :: minus a xt
let rec permute2 k x =
if k = 0 then [[]]
elif List.length x < k then []
else mapperm k x x
and mapperm k x = function
| [] -> []
| yh :: yt -> mapcons yh (permute2 (minus yh x)) (mapperm x yt)
and mapcons a ps qs =
match ps with
| [] -> qs
| ph :: pt -> a :: ph :: mapcons a pt qs
Related
I have to make a function that take a list and return the list but without the elements betweens the occurences.
For example: [1; 2; 3; 4; 2; 7; 14; 21; 7; 5] -> [1; 2; 7; 5]
I imagined that to make this I will take the head of the list, and then see
if there is another occurrence in the tail, so I browse the list and when I found the occurrence, I delete everything between them and I keep just one of them.
First I tried something like this:
let rec remove list = match list with
| [] -> []
| h::t -> if(List.mem h t) then
(*Here I would like to go through the list element by element to
find the occurence and then delete everything between*)
else
remove t
So for the part I don't succeed to do, I made a function which allows to slice a list between two given points, just like so:
let slice list i k =
let rec take n = function
| [] -> []
| h :: t -> if n = 0 then [] else h :: take (n-1) t
in
let rec drop n = function
| [] -> []
| h :: t as l -> if n = 0 then l else drop (n-1) t
in
take (k - i + 1) (drop i list);;
(*Use: slice ["a";"b";"c";"d";"e";"f";"g";"h";"i";"j"] 2 3;;*)
I also have this function that allows me to get the index of points in the list:
let index_of e l =
let rec index_rec i = function
| [] -> raise Not_found
| hd::tl -> if hd = e then i else index_rec (i+1) tl
in
index_rec 0 l ;;
(*Use: index_of 5 [1;2;3;4;5;6] -> return 4*)
But I don't really know how to combine them to get what I expect.
here is what I made :
let rec remove liste =
let rec aux l el = match l with
| [] -> raise Not_found
| x :: xs -> if el = x then try aux xs el with Not_found -> xs
else aux xs el in
match liste with
| [] -> []
| x :: xs -> try let r = x :: aux xs x in remove r with Not_found -> x :: remove xs;;
my aux function return the list which follow the last occurence of el in l. If you have any question or if you need more explanation just ask me in comment
A version that uses an option type to tell if an element appears further on in the list:
let rec find_tail ?(eq = (=)) lst elem =
match lst with
| x :: _ when eq x elem -> Some lst
| _ :: xs -> find_tail ~eq xs elem
| [] -> None
let rec remove ?(eq = (=)) lst =
match lst with
| [x] -> [x]
| x :: xs -> begin
match find_tail ~eq xs x with
| Some tail -> x :: remove ~eq (List.tl tail)
| None -> x :: remove ~eq xs
end
| [] -> []
Also lets you specify a comparison function (Defaulting to =).
Example: split [1;3;2;4;7;9];;
Output: ([1;3;7;9], [2;4])
I'm new to F# and I can't figure it out.
Can't use the partition built in function.
This is what I have so far:
let rec split xs =
match xs with
| [] -> [], []
| xs -> xs, []
| xh::xt -> let odds, evens = split xt
if (xh % 2) = 0 then xh::odds, xh::evens
else xh::odds, evens
Fixed code:
let rec split xs =
match xs with
| [] -> [], []
| xh::xt -> let odds, evens = split xt
if (xh % 2) = 0 then odds, xh::evens
else xh::odds, evens
*Thanks to #TheInnerLight for pointing out my errors: unreachable case and unnecessarily modifying odds
You can use the built-in List.partition function
let splitOddEven xs =
xs |> List.partition (fun x -> x % 2 <> 0)
splitOddEven [1;3;2;4;7;9];;
val it : int list * int list = ([1; 3; 7; 9], [2; 4])
If you want a recursive implementation, I'd probably go for a tail recursive implementation like this:
let splitOddEven xs =
let rec splitOddEvenRec oddAcc evenAcc xs =
match xs with
| [] -> oddAcc, evenAcc
| xh::xt ->
if (xh % 2) = 0 then splitOddEvenRec oddAcc (xh :: evenAcc) xt
else splitOddEvenRec (xh :: oddAcc) evenAcc xt
splitOddEvenRec [] [] xs
splitOddEven [1;3;2;4;7;9]
Note that this will give you the two resulting lists in reverse order so you might wish to reverse them yourself.
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then remove (x,l)
else isolate xs
I've already created functions memberof and remove, the only problem is that when line 6 remove(x,l) executes it doesn't continue with isolate(xs) for continued search through the list.
Is there a way to say,
if x then f(x) and f(y)
?
As you are using F# immutable lists, the result of remove needs to be stored somewhere:
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then
let xs = remove (x,l)
isolate xs
else isolate xs
To answer your more general question:
let f _ = ()
let f' z = z
let x = true
let y = 42
let z = 3.141
if x then
f y
f' z |> ignore
The ignore is needed here because in F# there are no statements, just expressions, so you can think of if x then f' z as
if x then
f' z
else
()
and thus the first branch needs to return () as well.
In addition to CaringDev's answer.
You may look at this simple solution.
It is worth note, that it's not a fastest way to do this.
let rec isolate (acc : 'a list) (l : 'a list) =
match l with
| [] -> acc
| head :: tail ->
if memberof (head, tail)
then remove (head, tail) |> isolate (acc # [head])
else isolate (acc # [head]) tail
let recursiveDistinct = isolate []
let uniqValues = recursiveDistinct [ 1; 1; 2; 3] //returns [1;2;3]
let isolate list =
let rec isolateInner searchList commonlist =
match searchList with
| x::xs ->
if (memberof commonlist x) then
isolateInner xs commonlist
else
let commonlist = (x :: commonlist)
isolateInner xs commonlist
| [] -> reverse commonlist
isolateInner list []
This is part of an answer to your larger problem.
Notice that this does not use remove. Since you have to pass over each item in the original list and list are immutable, it is better to create a new list and only add the unique items to the new list, then return the new list.
I'm trying to write a function that deletes the second occurrence of an element in a list.
Currently, I've written a function that removes the first element:
removeFirst _ [] = []
removeFirst a (x:xs) | a == x = xs
| otherwise = x : removeFirst a xs
as a starting point. However,I'm not sure this function can be accomplished with list comprehension. Is there a way to implement this using map?
EDIT: Now I have added a removeSecond function which calls the first
deleteSecond :: Eq a => a -> [a] -> [a]
deleteSecond _ [] = []
deleteSecond a (x:xs) | x==a = removeFirst a xs
| otherwise = x:removeSecond a xs
However now the list that is returned removes the first AND second occurrence of an element.
Well, assuming you've got removeFirst - how about searching for the first occurence, and then using removeFirst on the remaining list?
removeSecond :: Eq a => a -> [a] -> [a]
removeSecond _ [] = []
removeSecond a (x:xs) | x==a = x:removeFirst a xs
| otherwise = x:removeSecond a xs
You could also implement this as a fold.
removeNth :: Eq a => Int -> a -> [a] -> [a]
removeNth n a = concatMap snd . scanl go (0,[])
where go (m,_) b | a /= b = (m, [b])
| n /= m = (m+1, [b])
| otherwise = (m+1, [])
and in action:
λ removeNth 0 1 [1,2,3,1]
[2,3,1]
λ removeNth 1 1 [1,2,3,1]
[1,2,3]
I used scanl rather than foldl or foldr so it could both pass state left-to-right and work on infinite lists:
λ take 11 . removeNth 3 'a' $ cycle "abc"
"abcabcabcbc"
Here is an instinctive implementation using functions provided by List:
import List (elemIndices);
removeSecond x xs = case elemIndices x xs of
(_:i:_) -> (take i xs) ++ (drop (i+1) xs)
_ -> xs
removeNth n x xs = let indies = elemIndices x xs
in if length indies < n
then xs
else let idx = indies !! (n-1)
in (take idx xs) ++ (drop (idx+1) xs)
Note: This one cannot handle infinite list, and its performance may not be good for very large list.
I am reviewing implementations for some basic data structures and the algorithms operating on them. I guess the idiomatic F# code for Insertion Sort is very much like:
let rec insert x = function
| [] -> [x]
| y::ys -> if x<=y then x::y::ys
else y::(insert x ys)
and insertionSort = function
| [] -> []
| x::xs -> insert x (insertionSort xs)
let myLst = [8;3;3;5;-6;0;1;4;-3;2]
let result = myLst |> insertionSort
val result : int list = [-6; -3; 0; 1; 2; 3; 3; 4; 5; 8]
While I was trying to implement it with List.foldBack and only one recursive function, as below, and couldn't give me the correct result? Anyone can figure out where the problem lies?
let rec anotherInsertionSort lst =
List.foldBack(fun x (ys:list<_>) ->
if ys.IsEmpty then [x]
elif x <= ys.Head then x::ys
else ys.Head::x::anotherInsertionSort ys.Tail) lst []
Un-golfed from cfern's code:
let rec insert i = function
| h::t -> min h i::(insert (max h i) t)
| _ -> [i]
let insertionSort l = List.foldBack insert l []
As I said in my comment, the problem is that you're dropping x in your else branch. Here's one way to fix it:
let rec anotherInsertionSort lst =
List.foldBack(fun x ys ->
match ys with
| [] -> [x]
| y::_ when x <= y -> x::ys
| y::ys -> y::(anotherInsertionSort (x::ys))) lst []
Having said that, I like Daniel's approach better.