I'm trying to implement a function used to split a list into two equal-length halves (the problem assumes the list is of even length) in F#. Using the search function yielded a thread that deals with the exact same problem I'm trying to work through now:
Split list into two equal lists in F#
I'm trying to implement the solution given by the user Juliet, who provides a partial answer:
let cut l =
let rec cut = function
| xs, ([] | [_]) -> xs
| [], _ -> []
| x::xs, y::y'::ys -> cut (xs, ys)
cut (l, l)
Which returns the second half of the list. I'm trying to work out a way to return the first half, so I made some modifications:
let rec cut(xs, ys) =
let zs = []
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
x::zs
cut (xs, ys)
You can probably tell that F# is my first functional programming language, and I'm kinda confused as to how it works, exactly. Pattern-matching is a new thing for me, and I was never very good at recursion to start with.
From what I understand, the way pattern matching works is that it's basically a more versatile version of an if-then-else statement, where the code to the left of the -> is the conditional (the "if" bit), and everything to the right is the block of code to execute if the conditional check passes (the "then" bit).
What I'm not totally sure of is whether you're allowed to do things like this:
| x::xs, y1::y2::ys ->
x::zs
cut (xs, ys)
If pattern matching really does work like if statements, then it should be, since in an if statement it would look something like
if (x::xs && y1::y2::ys)
{
x::zs
cut (xs, ys)
}
Anyhow, it doesn't seem like the statement x::zs is allowed, since Visual Studio gives me a warning:
The result of this expression is implicitly ignored. Consider using "ignore" to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. let result = expr'.
I'm not sure what it means by that last part. I thought I had already declared the list as a local variable of the function in the line
let zs = []
All I'm trying to do is take the head of the list xs in each recursive iteration of the cut function and add it to another list zs, which when the base case is reached, would contain every element x passed over (in other words, the first half of the list), then return both xs (which contains the second half of the list) and the list containing the first half, but it doesn't seem like that's allowed?
Anyhow, it doesn't seem like the statement x::zs is allowed, since Visual Studio gives me a warning.
The expression x::zs is allowed, but Visual Studio is trying to tell you that it has no effect. x::zs creates a new list but then immediately discards it (it does not mutate the existing value!).
Based on the rest of the code provided, zs should contain the first half of the list, but zs will only ever contain the empty list [] because that's the only value it is assigned to. In a language like C#, you would simply mutate the list by appending to it but in F# you shouldn't do that. Since you're already using recursion, this is a sign that zs should be a parameter to your recursive function so that you can use the new value later. (I've found that some people understand recursion better if they think of it as a callback. When you recurse, it's like providing parameters to a callback function. Any values you want to accumulate during the recursion process need to be provided as parameters to your function.)
Putting this all together, I think what you want is something like this:
let rec cut(xs, ys, zs) =
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
cut (xs, ys, x::zs)
Typically, you'd hide this function inside a non-recursive function which sets up your arguments correctly:
let cut(xs, ys) =
let rec impl(xs, ys, zs) =
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
impl (xs, ys, x::zs)
impl(xs, ys, [])
Note: There's no need to use ,s to seperate arguments in F#. When you do this, you are actually declaring that a function has a single argument consisting of a tuple. This is not usually what you want and it prevents currying the function. All you need to use to separate arguments is whitespace:
let cut xs ys =
let rec impl xs ys zs =
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
impl xs ys (x::zs)
impl xs ys []
Here's a way to do it by adding another accumulator value that builds up the slow items into a list:
let cut l =
let rec loop acc rem =
match rem with
| xs, ([] | [_]) -> List.rev acc, xs
| [], _ -> [], []
| x::xs, y::y'::ys -> loop (x::acc) (xs, ys)
loop [] (l, l)
> cut [1;2;3;4;5;6]
([1; 2; 3], [4; 5; 6])
Related
I'm trying to self-learn some programming in a functional programming language and recently stumbled on the problem of generating all the permutations of length m from a list of length n, with repetition. Mathematically, this should result in a total of n^m possible permutations, because each of the m 'slots' can be filled with any of the n elements. The code I have currently, however, does not give me all the elements:
let rec permuts n list =
match n, list with
0, _ -> [[]]
| _, [] -> []
| n, h :: t -> (List.map (fun tt -> h::tt) (permuts (n-1) list))
# permuts n t;;
The algorithm basically takes one element out of a list with m elements, slaps it onto the front of all the combinations with the rest of the elements, and concatenates the results into one list, giving only n C m results.
For example, the output for permuts 2 [1;2;3] yields
[[1;1]; [1;2]; [1;3]; [2;2]; [2;3]; [3;3]]
whereas I actually want
[[1;1]; [1;2]; [1;3]; [2;1]; [2;2]; [2;3]; [3;1]; [3;2]; [3;3]]
-- a total of 9 elements. How do I fix my code so that I get the result I need? Any guidance is appreciated.
Your error appears on the second line of:
| n, h :: t -> List.map (fun tt -> h::tt) (permuts (n-1) list)
# permuts n t
Indeed, with this you are decomposing the set of n-tuples with k elements as the sum of
the set of (n-1)-tuples prefixed with the first element
the set of n-tuples with (k-1) elements
Looking at the cardinal of the three sets, there is an obvious mismatch since
k^n ≠ k^(n-1) + (k-1)^n
And the problem is that the second term doesn't fit.
To avoid this issue, it is probably better to write a couple of helper function.
I would suggest to write the following three helper functions:
val distribute: 'a list -> 'a list -> 'a list list
(** distribute [x_1;...;x_n] y returns [x_1::y;...x_n::y] *)
val distribute_on_all: 'a list -> 'a list list
(** distribute_on_all x [l_1;...;l_n] returns distribute x l_1 # ... # distribute x l_n *)
val repeat: int -> ('a -> 'a) -> 'a -> 'a
(** repeat n f x is f(...(f x)...) with f applied n times *)
then your function will be simply
let power n l = repeat n (distribute_on_all l) [[]]
In Haskell, it's very natural to do this using a list comprehension:
samples :: Int -> [a] -> [[a]]
samples 0 _ = [[]]
samples n xs =
[ p : ps
| p <- xs
, ps <- samples (n - 1) xs
]
It seems to me you never want to recurse on the tail of the list, since all your selections are from the whole list.
The Haskell code of #dfeuer looks right. Note that it never deconstructs the list xs. It just recurses on n.
You should be able to copy the Haskell code using List.map in place of the first two lines of the list comprehension, and a recursive call with (n - 1) in place of the next line.
Here's how I would write it in OCaml:
let perm src =
let rec extend remaining_count tails =
match remaining_count with
| 0 -> tails
| _ ->
(* Put an element 'src_elt' taken from all the possible elements 'src'
in front of each possible tail 'tail' taken from 'tails',
resulting in 'new_tails'. The elements of 'new_tails' are one
item longer than the elements of 'tails'. *)
let new_tails =
List.fold_left (fun new_tails src_elt ->
List.fold_left (fun new_tails tail ->
(src_elt :: tail) :: new_tails
) new_tails tails
) [] src
in
extend (remaining_count - 1) new_tails
in
extend (List.length src) [[]]
The List.fold_left calls may look a bit intimidating but they work well. So it's a good idea to practice using List.fold_left. Similarly, Hashtbl.fold is also common and idiomatic, and you'd use it to collect the keys and values of a hash table.
The motivating problem is: Code a lazy list whose elements are all possible combinations of 0 and 1 i.e. [0], [1], [0;0], [0;1], etc..
Working in OCaml, I've written auxiliary functions for generating the list of permutations of length n+1 given n and for converting a list into a lazy list. The problem comes from the final function in the below block of code:
type 'a seq =
| Nil
| Cons of 'a * (unit -> 'a seq)
let rec adder = function
| [] -> []
| [[]] -> [[0];[1]]
| xs::ys -> (0::xs)::(1::xs)::(adder ys)
let rec listtoseq = function
| [] -> Nil
| xs::ys -> Cons(xs, fun () -> listtoseq ys)
let rec appendq xq yq =
match xq with
| Nil -> yq
| Cons (x, xf) -> Cons (x, fun() -> appendq (xf ()) yq)
let genlist xs = appendq (listtoseq xs) (genlist (adder xs))
Calling genlist [[0];[1]] results in a stack overflow. The issue seems to be that since genlist is an infinite loop I want to delay evaluation, yet evaluation is needed for appendq to work.
If this were a problem where one element is added to the lazy list at a time I could solve it, but I think the difficulty is that each set of length n permutations must be added at a time, and thus I don't know any other solution besides using an append function.
One way to look at your problem is that appendq isn't lazy enough. You can make things work if you define a function appendqf with this type:
'a seq -> (unit -> 'a seq) -> 'a seq
In other words, the second parameter isn't a sequence. It's a function that returns a sequence.
(Note that this type, unit -> 'a seq, is what actually appears inside a Cons.)
I tried this and it works for me.
I'm trying to implement merge function in OCaml using Tail recursion but I face awkward results. Could anyone help me out with this. Thanks in advance.
let rec merge_helper l1 l2 accum =
match l1 with
[] -> l2#accum
| hd::tl -> (match l2 with
[] -> l1#accum
|x::xs -> merge_helper tl xs l1#l2#accum);;
let merge l1 l2 = merge_helper l1 l2 [];;
merge [1;2;4] [3;4;5];;
- : int list = [4; 5; 2; 4; 4; 5; 1; 2; 4; 3; 4; 5]
First of all your implementation doesn't run in a constant stack space. The xs # ys operation is not tail-recursive, and will make List.length xs calls (thus using this amount of stack frames). Also, the merge function usually preserves the ordering. So you need to have a comparison function, that will compare elements of the list. It is not absolutely clear, what you're expecting from you merge function, and why you classify your result as weird. For me the result matches with the code. What looks very strange to me is that although you're deconstructing l1 and l2 you're not using the result of the deconstruction and adds the whole lists l1 and l2 to the accumulator.
The approach should be the following, take an element from the first list, add this element to the accumulator, and switch the lists. So the induction step of the algorithm is the following:
let rec loop acc xs ys = match xs with
...
| x::xs -> loop (x::acc) ys xs
But if you want to merge two sorted lists preserving the order, then you need to take the smallest element of the two lists at each step.
let merge cmp xs ys =
let rec loop xs ys zs = match xs,ys with
| [],ss|ss,[] -> List.rev_append zs ss
| x :: txs, y :: tys ->
if cmp x y <= 0
then loop txs ys (x::zs)
else loop xs tys (y::zs) in
loop xs ys []
Here in the induction step, we take the smaller element, and continue with the two lists: the tail of the owner of the smaller element (because it is moved into the accumulator), and the second list is taken fully (because nothing is accumulated from it). Since we're prepending elements, they will be in a reversed order, so we will need to something to reverse the result (a usual trade off for tail-recursion). The base case, allows us to short-circuit our algorithm, when one or another list is shorter, and we don't need any more to compare them one-by-one, and can just append the rest part of the longer list to the accumulator zs. We use List.rev_append to append the leftover tail of the list to our accumulator. This function will prepend the reversed version of the first list to the second.
Since I had problems with stack overflows due to a non-tail recursion, I used the continuations so as to make sorting of large list feasible.
I implemeneted the sorting this way (you can see the whole code here: http://paste.ubuntu.com/13481004/)
let merge_sort l =
let rec merge_sort' l cont =
match l with
| [] -> cont []
| [x] -> cont [x]
| _ ->
let (a,b) = split l
in
merge_sort' a
(fun leftRes -> merge_sort' b
(* OVERFLOW HERE *) (fun rightRes -> cont (merge leftRes rightRes) )
)
in merge_sort' l (fun x -> x)
I get a stack overflow nevertheless, in the indicated line.
What am I doing wrong?
(#) of OCaml's standard library is not tail recursive. merge function in your code http://paste.ubuntu.com/13481004/ uses (#), and this is the cause of the stack overflow.
list.mli says:
val append : 'a list -> 'a list -> 'a list
(** Catenate two lists. Same function as the infix operator [#].
Not tail-recursive (length of the first argument). The [#]
operator is not tail-recursive either. *)
but unfortunately this fact is not written in pervasives.mli where (#) is really declared:
val ( # ) : 'a list -> 'a list -> 'a list
(** List concatenation. *)
This is not good :-( I have filed an issue for it at OCaml dev page.
I redefined (#) as fun x y -> rev_append (rev x) y then your code runs w/o stack overflow. More elegantly, you can replace codes like (rev a) # l by rev_append a l.
P.S. (#) in pervasives.mli will be commented as "not tail recursive" in the next release of OCaml.
How can I remove nils from this list ,lets say i get:
[{"some","other",[]},nil,{{"more","somemore",[]},nil,nil}]
In the end I would like to extract only the first elements from the long tuples and put them on a list,
Something like:
["some", "more"]
You can remove nils from the list using function like that:
filter_out_nils(Data) when is_list(Data) ->
Pred = fun(Element) -> Element /= nil end,
lists:filter(Pred, Data).
This function does not remove nils within tuples though.
And you can use a couple of functions to extract every first non tuple element in you list (like strings "some" and more):
extract_first_elements(Data) when is_list(Data) ->
lists:map(fun extract_first_non_tuple_element/1, Data).
extract_first_non_tuple_element({})-> {};
extract_first_non_tuple_element(Data) when is_tuple(Data)->
case element(1, Data) of
First when is_tuple(First) -> extract_first_non_tuple_element(First);
Other -> Other
end.
Function extract_first_non_tuple_element is recursive, because in your example tuple can be nested.
So to test this functions:
Data1 = [{"some","other",[]}, nil, {{"more","somemore",[]}, nil, nil}].
filter_out_nils(Data1).
[{"some","other",[]},{{"more","somemore",[]},nil,nil}] % resulting list without nils
Data2 = extract_first_elements(Data1).
["some","more"] % extracted first elements
Update.
To remove nils from nested tuples we can use function like that:
filter_out_nils_from_tuple(Data) when is_tuple(Data) ->
TList = tuple_to_list(Data),
Fun = fun(Element, Acc) ->
case Element of
nil -> Acc;
Tuple when is_tuple(Tuple) -> Acc ++ [filter_out_nils_from_tuple(Tuple)];
Other -> Acc ++ [Other]
end
end,
Result = lists:foldl(Fun, [], TList),
list_to_tuple(Result).
Filtering out nils and getting the first element of nested tuples in your example can be achieved with a single recursive function, with a clause for the nil case:
f([Item | T], Acc) when is_tuple(Item) -> f([element(1, Item) | T], Acc);
f([nil | T], Acc) -> f(T, Acc); % filter out nil
f([Other | T], Acc) -> f(T, [Other | Acc]);
f([], Acc) -> lists:reverse(Acc).
Since you added erlang-shell tag, please note this solution will not work directly in the shell. Indeed, recursive functions in the shell shall be written as functions taking a function (themselves) as an argument (cf: How do you write a fun that's recursive in Erlang?).
F = fun(F, [Item | T], Acc) when is_tuple(Item) ->
F(F, [element(1, Item) | T], Acc);
(F, [nil | T], Acc) -> F(F, T, Acc);
(F, [Other | T], Acc) -> F(F, T, [Other | Acc]);
(_F, [], Acc) -> lists:reverse(Acc)
end.
F(F, List, []).
Please also note that this solution has specific behaviors for cases not covered in your question:
It will crash with a function clause error if the input list contains an empty tuple. Yet, this might be a desired behavior. Otherwise, you can simply add a new function clause to handle it as desired (should empty tuples be filtered out or returned?).
It will accept and return non-tuple elements in the list (except nil), e.g. f(["some", "more"], []). To avoid this, you would need a slightly different logic.
It will crash if the argument is not a proper list.