what is wrong with my unpair implementation? - f#

I'm trying to figure out WHY i'm getting the error below more than I am interested in a correct implementation of my method.
I have the following f# code that is supposed to unpair a list of tuples into a list containing all the items in the tuples like so:
let unpair l =
let rec loop acc l =
match l with
| [] -> acc
| (x,y)::tl ->
loop (acc # x # y) tl
loop [] l
//should print:
// [1 2 3 4 5 6]
printf "["
List.iter (printf "%A") (unpair [(1, 2); (3, 4); (5, 6)])
printfn "]"
I get the following error for each of my ints when calling unpair:
This expression was expected to have type 'a list but here has type int
Why is it expecting 'a list?

The problem is in the following expression
acc # x # y
The # is used to combine list values together yet here x and y are typed to int. What you're looking for is the :: operator which will add items to a list. Additionally you are building up the list backwards in that expression. Use the following and it should fix your issue
x :: y :: acc

As JaredPar explains, you need to use x::acc to add elements to the accumulator. If you want to append elements to the end, you could write acc # [x], but that's very inefficient, as it needs to copy the whole list for every single element.
The usual solution is to add elements to the front and then reverse the list at the end of the processing:
let unpair l =
let rec loop acc l =
match l with
| [] -> List.rev acc // NOTE: Reverse the list here
| (x,y)::tl ->
loop (y::x::acc) tl // Add elements to the front
loop [] l
This is a lot more efficient than using acc # [x], because it keeps adding elements to the front (which takes just a small constant time) and then creates a single copy of the whole list at the end.
The same function can be also nicely & efficiently implemented using sequence expressions:
let unpair l =
[ for x, y in l do
yield x
yield y ]

Related

Why doesn't this sequence generation work?

I'm facing with the generation of all the k-combinations (without repetition) of a list of elements. Beside the possible optimization in the code I wrote this function which I was almost sure it should work:
// comb :: int -> 'a list -> seq<'a list>
// Generates a sequence of all combinations (no repetition)
let comb k xs =
// subs :: 'a list -> seq<'a list>
// Splits a list in its subsequent non-empty tails
let rec subs xs =
seq {
match xs with
| _::ys -> yield xs
yield! subs ys
| _ -> yield! []
}
let rec comb' k xs rs =
seq {
for zs in subs xs do
match k, zs with
| 0, _ -> yield rs // Solution reached
| _ when k > List.length zs -> yield! [] // Safety (and optimizing) guard
| _, y::ys -> yield! comb' (k - 1) ys (y::rs) // Let's go deeper
| _ -> yield! [] // Not a solution
}
comb' k xs []
The idea behind this algorithm is to "traverse" the tree of all possible combinations and select only the ones with k elements; the subs function is used to generate the sub-sets of elements to generate the sub-trees in the same level; that is, calling:
Seq.toList <| subs [1..3];;
produces:
[[1;2;3];[2;3];[3]]
Maybe this part is a bit confusing, but it shouldn't be part of the problem and I don't think the issue is there.
The algorithm doesn't keep the order of the elements, but it's not necessary for my purpose.
Making a simple test case:
Seq.toList <| comb 2 [1..3];;
I was expecting the three solutions:
[[2;1];[3;1];[3;2]]
but actually it returns only:
[[2;1]]
I debug a little with VS Code, but I didn't really understand how the execution flows.
Does anybody see where the problem is?
Update
I realized that I badly exposed the concept behind the algorithm.
I visualized the solution to the problem like a search tree; at every level the root of a subtree contains the solution obtained by the concatenation of the head of all the remaining tails (subs results) and the list of the parent node.
Comparing the size of the tails and the current value of k I am able to understand which branches can actually contain solutions.
Your code is nearly right. The only issue is that when xs is empty in comb', then subs will be empty (since there are no non-empty tails) even when k is 0, but you should be yielding rs in that case, too.
This can easily be fixed by testing if k is 0 outside of the for loop and yielding rs there, and then putting the for loop into the else branch (where now you only need to match on zs):
let rec comb' k xs rs =
seq {
if k = 0 then yield rs
elif k <= List.length xs then
for zs in subs xs do
match zs with
| y::ys -> yield! comb' (k - 1) ys (y::rs) // Let's go deeper
| [] -> yield! [] // Not a solution
}
Well, your solution is very confusing, and it's no wonder that it produces incorrect results. Very hard to understand, very hard to follow.
Problem 1: subs doesn't actually produce all possible subsets. Look: in your very own experiment you're saying that subs [1..3] produces [[1;2;3]; [2;3]; [3]]. But this is incorrect: [1;3] is also a possible subset, but it's missing!
If you look carefully at what subs is actually doing, you'll see that at every iteration it emits the current value of xs, and then calls itself passing the tail of xs as argument. This, very predictably, leads to a sequence of all tails of the original list.
One obvious way to produce all possible subsets is by, at every iteration level, to produce a sequence of lists with one element removed:
let rec subs xs =
if List.isEmpty xs then Seq.empty
else
seq {
yield xs
for i in 0..(List.length xs - 1) do
let xsWithoutI = (List.take i xs) # (List.skip (i+1) xs)
yield! subs xsWithoutI
}
But of course, this will generate repetitions:
> subs [1..3] |> Seq.toList
val it : int list list =
[[1; 2; 3]; [2; 3]; [3]; [2]; [1; 3]; [3]; [1]; [1; 2]; [2]; [1]]
I will leave it as an exercise to come up with a way to exclude repetitions.
Problem 2 the function comb' doesn't make sense at all. At every iteration, zs is one of the possible subsequences (from subs), which you then match with y::ys, thus making y the first element of that subsequence, and ys - its tail. Then you prepend the first element of the subsequence to the result, and recur. This means that you're gradually building up the result out of first elements of every subsequence, but in reverse order (because you're prepending). So naturally, the result is [2;1]: 2 is the first element of the second subsequence, and 1 is the first element of the first subsequence.
The approach doesn't make sense to me at all. I don't see what the thought process could have been that lead to this implementation.
If you have a sequence of all posisble subsequences (from subs), and you want only those that are k elements long, why not just filter by that?
let comb' k xs = subs xs |> Seq.filter (fun s -> List.length s = k)
> comb' 2 [1..3]
val it : seq<int list> = seq [[2; 3]; [1; 3]; [1; 2]]

How do I get the max value from a list with a function that takes two arguments?

Define the function max2 that takes two integers as arguments and returns the largest of them.
I did this: let max2 x y = if x < y then y else x this I belive is correct
Then define the function max_list that returns the largest of the elements in a nonempty list of integers by calling max2. For the empty list, it should abort with an error message ( raising an exception)
I did this: let list = [3;4] let max_list = if list.IsEmpty then 0 else max2 list.Item(0) list.Item(1) but this wont work if the list is more then two elements. I dont want to use any object-orientated stuff. What is the correct answer?
The correct answer is that you should read about recursion with lists.
F# list is built up gradually using empty list [] and cons (::) constructor. For example,
[3; 4] is a syntactic sugar for 3::4::[]. We often use pattern matching on lists in writing recursive functions.
Here is a recursive function following your requirements closely:
let rec max_list xs =
match xs with
// The function aborts with an error message on empty lists
| [] -> invalidArg "xs" "Empty list"
// Return immediately on a singleton list
| [x] -> x
// xs has at least two elements, call max_list
// on the bigger element of the first two ones and the rest of the list
| x1::x2::xs' -> max_list((max2 x1 x2)::xs')
On a side note, there is a built-in generic max function which also works on integers.
A simple recursive solution:
let max2 x y = if x < y then y else x
let max_list list =
let rec loop hi list =
match list with
| h::t -> let hi = max2 h hi
loop hi t
| [] -> hi
match list with
| h::t -> loop h t
| [] -> invalidArg "list" "Empty list"
Test in FSI:
> max_list [3;4;5;1;2;9;0];;
val it : int = 9
For each element in the list, compare it to the previous highest ('hi'). Pass the new highest and the rest of the list into the loop function, until the input list is empty. Then just return 'hi'.

Confused with F# List.Fold (powerset function)

I understand and wrote a typical power set function in F# (similar to the Algorithms section in Wikipedia)
Later I found this implementation of powerset which seems nice and compact, expect that I do not understand it.
let rec powerset = function
| [] -> [[]]
| h::t -> List.fold (fun xs t -> (h::t)::t::xs) [] (powerset t);
I broke this down to a 1 step non-recursive function to find the powerset of [1;2] and hardcoded the value of power set of 2 at the end [[2]; []]
let right = function
| [] -> [[]]
| h::t -> List.fold (fun acc t -> (h::t)::t::acc) [] [[2]; []];
The output is [[1]; []; [1; 2]; [2]] which is correct.
However I was expecting List.Fold to output [[1; 2]; []; [1; 2]; [2]].
Since I was not certain about the 't', I modified the variable names, and I did get what I had expected. Of course this is not the correct powerset of [1;2].
let wrong = function
| [] -> [[]]
| h::t -> List.fold (fun acc data -> (h::t)::data::acc) [] [[2]; []];
For me 't' (the one withing fun and not the h::t) is simply a name for the second argument to 'fun' but that is obviously not the case. So what is the difference in the "right" and "wrong" F# functions I have written ? And what exactly does 't' here refer to ?
Thank you ! (I am new to F#)
In your "right" example, t is originally the name of the value bound in the pattern match, but it is hidden by the parameter t in the lambda expression passed to List.fold. Whereas in your "wrong" example, t is captured as a closure in the lambda expression. I think maybe you don't intend this capture, instead you want:
//now it works as you expect, replaced "t" with "data" in your lambda expression.
let wrong = function
| [] -> [[]]
| h::t -> List.fold (fun acc data -> (h::data)::data::acc) [] [[2]; []];
let rec powerset = function
| [] -> [[]]
| h::t -> List.fold (fun xs t -> (h::t)::t::xs) [] (powerset t);
here is the understanding/english translation of the code:
if the list (you want to power) is empty, then return a list, which contains an empty list in it
if the list is h::t (with head h and the rest as t, so h is an element and t is a list). then:
A. (powerset t): calculate the power set of t
B. (fun xs t -> (h::t)::t::xs) means that you apply/fold this function to the (powerset t). more details: xs is an accumulator, it is initialized to []. xxx::xs means you add something to an existing powerest xs. Here xxx is (h::t)::t, which are two elements to be added to the head of xs. (h::t) means add head to t and t means each element in (powerset t). <- the confusing part lies in t, the t in (powerset t) is the rest of the list, while the other t means an element in (powerset t).
here is an imperative translation of the fold function :
let h::t = list
let setfort = powerset t
xs <- []
foreach s in setfort do
xs <- xs.add(t) // t is a valid subset of list
xs <- xs.add(h::t) // t with h is also a valid subset of list
t is a variable bound by pattern matching. List.fold is a fancy way of avoiding explicit looping. Now, go and read some introductory tutorials about F#.

F# return element pairs in list

I have been looking for an elegant way to write a function that takes a list of elements and returns a list of tuples with all the possible pairs of distinct elements, not taking into account order, i.e. (a,b) and (b,a) should be considered the same and only one of them be returned.
I am sure this is a pretty standard algorithm, and it's probably an example from the cover page of the F# documentation, but I can't find it, not even searching the Internet for SML or Caml. What I have come up with is the following:
let test = [1;2;3;4;5;6]
let rec pairs l =
seq {
match l with
| h::t ->
yield! t |> Seq.map (fun elem -> (h, elem))
yield! t |> pairs
| _ -> ()
}
test |> pairs |> Seq.toList |> printfn "%A"
This works and returns the expected result [(1, 2); (1, 3); (1, 4); (1, 5); (1, 6); (2, 3); (2, 4); (2, 5); (2, 6); (3, 4); (3, 5); (3, 6); (4, 5); (4, 6); (5, 6)] but it looks horribly unidiomatic.
I should not need to go through the sequence expression and then convert back into a list, there must be an equivalent solution only involving basic list operations or library calls...
Edited:
I also have this one here
let test = [1;2;3;4;5;6]
let rec pairs2 l =
let rec p h t =
match t with
| hx::tx -> (h, hx)::p h tx
| _ -> []
match l with
| h::t -> p h t # pairs2 t
| _ -> []
test |> pairs2 |> Seq.toList |> printfn "%A"
Also working, but like the first one it seems unnecessarily involved and complicated, given the rather easy problem. I guess my question is mor about style, really, and if someone can come up with a two-liner for this.
I think that your code is actually pretty close to an idiomatic version. The only change I would do is that I would use for in a sequence expression instead of using yield! in conjunction with Seq.map. I also usually format code differently (but that's just a personal preference), so I would write this:
let rec pairs l = seq {
match l with
| h::t -> for e in t do yield h, elem
yield! pairs t
| _ -> () }
This is practically the same thing as what Brian posted. If you wanted to get a list as the result then you could just wrap the whole thing in [ ... ] instead of seq { ... }.
However, this isn't actually all that different - under the cover, the compiler uses a sequence anyway and it just adds conversion to a list. I think that it may be actually a good idea to use sequences until you actually need a list (because sequences are evaluated lazilly, so you may avoid evaluating unnecessary things).
If you wanted to make this a bit simpler by abstracting a part of the behavior into a separate (generally useful) function, then you could write a function e.g. splits that returns all elements of a list together with the rest of the list:
let splits list =
let rec splitsAux acc list =
match list with
| x::xs -> splitsAux ((x, xs)::acc) xs
| _ -> acc |> List.rev
splitsAux [] list
For example splits [ 1 .. 3 ] would give [(1, [2; 3]); (2, [3]); (3, [])]. When you have this function, implementing your original problem becomes much easier - you can just write:
[ for x, xs in splits [ 1 .. 5] do
for y in xs do yield x, y ]
As a guide for googling - the problem is called finding all 2-element combinations from the given set.
Here's one way:
let rec pairs l =
match l with
| [] | [_] -> []
| h :: t ->
[for x in t do
yield h,x
yield! pairs t]
let test = [1;2;3;4;5;6]
printfn "%A" (pairs test)
You seem to be overcomplicating things a lot. Why even use a seq if you want a list? How about
let rec pairs lst =
match lst with
| [] -> []
| h::t -> List.map (fun elem -> (h, elem)) t # pairs t
let _ =
let test = [1;2;3;4;5;6]
printfn "%A" (pairs test)

Merge/join seq of seqs

Slowly getting the hang of List matching and tail recursion, I needed a function which 'stitches' a list of lists together leaving off intermediate values (easier to show than explain):
merge [[1;2;3];[3;4;5];[5;6;7]] //-> [1;2;3;4;5;6;7]
The code for the List.merge function looks like this:
///Like concat, but removes first value of each inner list except the first one
let merge lst =
let rec loop acc lst =
match lst with
| [] -> acc
| h::t ->
match acc with
| [] -> loop (acc # h) t
| _ -> loop (acc # (List.tl h)) t //first time omit first value
loop [] lst
(OK, it's not quite like concat, because it only handles two levels of list)
Question: How to do this for a Seq of Seqs (without using a mutable flag)?
UPDATE (re comment from Juliet):
My code creates 'paths' composed of 'segments' which are based on an option type:
type SegmentDef = Straight of float | Curve of float * float
let Project sampleinterval segdefs = //('clever' code here)
When I do a List.map (Project 1.) ListOfSegmentDefs, I get back a list where each segment begins on the same point where the previous segment ends. I want to join these lists together to get a Path, keeping only the 'top/tail' of each overlap - but I don't need to do a 'Set', because I know that I don't have any other duplicates.
This is essentially the same as your first solution, but a little more succinct:
let flatten l =
seq {
yield Seq.hd (Seq.hd l) (* first item of first list *)
for a in l do yield! (Seq.skip 1 a) (* other items *)
}
[Edit to add]:
If you need a List version of this code, use append |> Seq.to_list at the end of your method:
let flatten l =
seq {
yield Seq.hd (Seq.hd l) (* first item of first list *)
for a in l do yield! (Seq.skip 1 a) (* other items *)
} |> Seq.to_list
let merge = function
| [] -> []
| xs::xss -> xs # [for _::xs in xss do yield! xs]
or:
let merge = function
| [] -> []
| xs::xss -> xs # List.collect List.tail xss

Resources