I wrote a simple function in Erlang which converts a tuple to list. But I don't understand why pattern matching order matters here :
Example
tupleToList(Tuple) -> tupleToList(Tuple, size(Tuple), []).
tupleToList(_, 0, L) -> L;
tupleToList(Tuple, S, L) -> tupleToList(Tuple, S - 1, [element(S, Tuple) | L]).
Why is the following code not correct?
tupleToList(Tuple) -> tupleToList(Tuple, size(Tuple), []).
tupleToList(Tuple, S, L) -> tupleToList(Tuple, S - 1, [element(S, Tuple) | L]);
tupleToList(_, 0, L) -> L.
Because that's how functions work in Erlang:
If the function is found, the function clauses are scanned sequentially until a clause is found that fulfills both of the following two conditions:
The patterns in the clause head can be successfully matched against the given arguments.
The guard sequence, if any, is true.
Since variables match everything, and there's no guard sequence, the tupleToList(Tuple, S, L) clause is always chosen in the second case, before the tupleToList(_, 0, L) is ever considered.
Related
I am new to PureScript so I am re-creating some basic functions, and I wanted to recreate "takeEnd" function which takes specified number of elements from the end of the list.
Here is solution I wrote:
takeEnd :: forall a. Int -> List a -> List a
takeEnd _ Nil = Nil
takeEnd n l = go n Nil $ reverse l where
go _ new Nil = new
go 0 new _ = new
go n new (x : xs) = go (n - 1) (x : new) xs
And here is a solution I found in a book:
takeEnd :: forall a. Int -> List a -> List a
takeEnd _ Nil = Nil
takeEnd n = go >>> snd where
go Nil = Tuple 0 Nil
go (x : xs) = go xs
# \(Tuple c nl) -> Tuple (c + 1) $ if c < n then x : nl else nl
I am interested in which version is more efficient? If I am not mistaken I believe also that second version is not tail optimized
The second solution does a single traversal of the list but is not tail recursive, so creates stack frames.
The first solution looks incorrect and gives the elements backwards. So it should do one traversal of the whole list and then a traversal of n, then possibly another reverse - so it is less efficient in terms of time.
PureScript often makes you decide between these efficiencies, due to strict evaluation. Could you blow the stack with the size of your list? If so, you have to stick with the theoretically slower, first solution.
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.
Learning OCaml from here.
I want to verify if I have understood how this snippet of OCaml code works
List.fold_left (fun acc x -> acc + x) 0 [ 1; 2; 3; 4 ]
I have an intuition that this is an equivalent to the reduce function in Python. Specifically, I think it is equivalent to
reduce(lambda x, y: x + y, [1, 2, 3])
The anonymous function is taking two parameters - acc and x and returns a single value acc + x. I understand that initially, the first argument acc will be 0 but how does it know that the second argument has to be the first element of the list?
What I think is happening is that fold_left provides the two arguments to the anonymous function and then recursively calls itself with new arguments until the list becomes empty.
To confirm this I saw this.
When I define a function like let inc x = x + 1 I get something like val inc : int -> int = <fun> but in this case the signature is : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
What is 'a and how should I interpret this function signature so that List.fold_right f [a1; ...; an] b becomes f a1 (f a2 (... (f an b) ...))?
You are asking many questions.
I'm pretty sure that Python reduce is a fold, so your intuition is probably right.
You ask "how does it know that the second argument has to be the first element of the list?" Unfortunately, I don't think this is a well formed question. There's no "it" that knows anything. Most likely the answer is given by the definition of fold_left. It knows what to do because somebody wrote the code that way :-)
Here is the definition of fold_left from the standard library:
let rec fold_left f accu l =
match l with
[] -> accu
| a::l -> fold_left f (f accu a) l
In some sense, this should answer all your questions.
The type 'a in the type of fold_left is the type of the accumulator. The point is that you can use any type you want for the accumulator. This is why the fold is so powerful. As long as it matches the values accepted and returned by the folded function, it can be anything you want.
If I remember correctly, reduce is a simpler version of fold, which takes the first element of the list as starting element. I'd define it this way:
let reduce f = function
| x::xs -> fold_left f x xs
| [] -> failwith "can't call reduce on empty lists!"
If you enter it in OCaml, it will display its type:
val reduce : ('a -> 'a -> 'a) -> 'a list -> 'a
You can contrast it with fold_left's type:
('b -> 'a -> 'b) -> 'b -> 'a list -> 'b
The type variables 'a and 'b here mean that they can stand for any type. In your example, both 'a and 'b become int. If we insert the types, fold_left has the signature:
(int -> int -> int) -> int -> int list -> int
That's what we expected: + is a function which takes two ints and returns a new one, 0 is an int and the [1;2;3;4;] is a list of ints. The case that fold_left has two type variables and reduce only has one already gives a hint that it is more general. To see why we can look at the definition of reduce. Since the starting element of the fold is an element of the list, the types 'a' and 'b must be the same. That's fine for summing up elements, but say, we'd like to construct an abstract syntax tree for our summation. We define a type for this:
type exp = Plus of exp * exp | Number of int
Then we can call:
fold_left (fun x y -> Plus (x, (Number y))) (Number 0) [1; 2; 3; 4]
Which results in the expression:
Plus (Plus (Plus (Plus (Number 0, Number 1), Number 2), Number 3), Number 4)
A benefit of this tree is that you can nicely see what is applied first (0 and 1) - in case of addition this is not a problem, since it is associative (this means a+(b+c) = (a+b)+c) which is not the case for subtraction (compare e.g. 5-(3-2) and (5-3)-2).
If you want to do something similar with reduce, you will notice that OCaml complains about type errors:
reduce (fun x y -> Plus (x, (Number y))) [1; 2; 3; 4] ;;
Error: This expression has type exp but an expression was expected of type
int
In this case, we can wrap each integer as an expression in our input list, then the types agree. Since we already have Numbers, we don't need to add the Number constructor to y:
let wrapped = map (fun x -> Number x) [1; 2; 3; 4] in
reduce (fun x y -> Plus (x, y)) wrapped
Again, we have the same result, but we needed an additional function call to map. In the case of fold_left, this is not necessary.
P.S.: You might have noticed that OCaml gives the type of fold_left as ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a. I guess you will quickly realize that the name of the type variables doesn't play a role. To make it easier to compare, I switched the names such that the function is always applied to a list of 'a.
A little late, but the comparison between OCaml's folds and Python's reduce may be easier if you incorporate reduce's initializer argument.
Summing a list of ints in OCaml using a fold:
let sum = List.fold_left (+) 0 [1; 2; 3]
And using reduce in Python.
from functools import reduce
sum = reduce(int.__add__, [1, 2, 3], 0)
Here you can see the order of arguments is a bit different, but they're all there.
Python feels it's less likely you'll need the initializer, so leaves it at the end as an optional argument as a convenience. OCaml features the list as the last argument also as a convenience, as partial application makes it easy to write something like a sum function.
let sum = List.fold_left (+) 0
Rather than:
let sum lst = List.fold_left (+) 0 lst
I'm trying to find the largest value of a list using tail recursion. I can't use any auxiliary functions, though...so it must be done using recursion. I've written a function to find the max, starting from the head, but don't know how to implement it starting from the tail!
lmax [] = error "empty list"
lmax [x] = x
lmax (x::y::xs) =
if x > y then lmax (x::xs)
else lmax (y::xs)
The term "tail recursion" has nothing to do with the tail of a list, it is about the position of a function call.
You could say that a function call is in tail position, or that it is a tail call, if it's the last thing to happen in a function, i.e. no other computations depend on it.
Compare
fun foo xs = List.length xs
and
fun bar xs = 1 + List.length xs
In the first, the call to List.length is in tail position, because its result is returned immediately.
In the second, since we add 1 to the length, the call isn't a tail call.
"Tail recursion" is when a recursive function call is a tail call.
So you're in luck: your function already is tail recursive, since both conditional branches just return the value of a recursive call.
fun lmax l = let
fun lmaxh [] a = a
| lmaxh (x::xs) a = lmax xs Int.max(x,a)
in
lmaxh l 0
end
This works, assuming that the values are nonnegative integers.
Implementing tail recursion optimizes efficiency, because one doesn't have to evaluate and "pop-off" the stack after creating the recursive calls.
In general, to use tail-recursion, you must store some "memory" from prior computations to compare with in the current one, and update it for future computations, so as to immediately exit the function in the base case.
As such, your function is already tail recursive.
However, here is a tail-recursive maxList function, more in the spirit of SML :
fun maxList l =
let
fun maxListHelper l acc =
case l of
[] => acc
| x :: xs' => if x > acc
then (maxListHelper xs' x)
else (maxListHelper xs' acc)
in
case l of
[] => error "Empty List!"
| x :: xs' => maxListHelper xs' x
end
Your function is written in a very Haskell-like syntax with different cases handled on different lines without being explicitly declared as nested cases inside a function definition. This is quite alright, but is usually not done in SML.
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.