My task is to take a list and then reverse it recursively, using one parameter.
What I have arrived at is this solution:
def reverse(l) do
[head | tail] = l
cond do
tail == [] ->
head
true ->
[reverse(tail) , head]
end
end
I have attempted having a | instead of a comma in the true statement, but to no avail.
The problem with this solution is that it prints out the following when inputting [1,2,3,4,5]:
[[[[5, 4], 3], 2], 1]
It doesn't actually add the head part to the list aside from when returning the final value of the list. (in this case 5)
One cannot expect implicit flattening for [list, elem] as you do in [reverse(tail), head].
The former is a list, and this is why you receive nested lists back.
One way to approach the problem would be to indeed add lists one to another with reverse(tail) ++ [head]. It’s not efficient though because it would produce new lists on each step and is not tail-recursive.
The proper solution would be to introduce an accumulator to collect the processed items
def reverse(input, acc \\ [])
def reverse([], acc), do: acc
def reverse([head | tail], acc) do
reverse(tail, [head | acc])
end
reverse([1, 2, 3])
#⇒ [3, 2, 1]
I personally like to use pattern matching in this way instead of the cond as I feel like it makes it easier to reason about it.
defmodule M do
def reverse(list) do
reverse_helper(list, [])
end
defp reverse_helper([], reversed) do
reversed
end
defp reverse_helper([h|t], reversed) do
reverse_helper(t, [h|reversed])
end
end
For fixing your solution you could use List.flatten:
#spec reverse(list()) :: list()
def reverse([]), do: []
def reverse([head | tail]) do
cond do
tail == [] ->
[head]
true ->
List.flatten(reverse(tail) ++ head)
end
end
Flatten for example takes [1, [2]] and returns [1, 2].
But this solution is not efficient. You could use #aleksei-matiushkin solutions or you can use foldl which is tail recursive:
#spec reverse_fold(list()) :: list()
def reverse_fold(l) do
List.foldl(l, [], fn x, acc ->
[x | acc]
end)
end
Related
I have a function that takes in a list and then puts elements into two different lists based on a condition. However, when I check the returned lists they are always empty. Why is this happening?
fun divide_list(l1: type list): (type list, type list) =
let
val count = ref 0
and list1 = nil
and list2 = nil
in
while !count <> 8 do (
if !count % 2 = 0 then
list1 # [List.nth(l1, !count)]
else
list2 # [List.nth(l1, !count)];
count := !count + 1
);
(list1, list2)
end
The output I get after running this is as follows:
val it = ([],[]) : type list * type list
You're not modifying the lists, you're creating new lists that are discarded. In order to achieve what you want, you'd need to also wrap the lists in references: and list1 = ref [] and list2 = ref []. Then, at each instance where you intend to modify them, you use := (as you have for modifying the count). Note that you'd rewrite the tuple you're returning to fetch the value held by each reference as well: (!list1, !list2).
As a sidenote, it is regrettable that Standard ML does not inform you of this. In OCaml, for example, the typing rule for sequencing expressions e ; e' ensures e evaluates to () : unit due to the way it's desugared (let () = e in e'). So, the OCaml analogue to your code wouldn't even typecheck.
I would dispense with the ref based solution entirely and do something using a fold, carrying the index:
fun divide xs =
let
fun choose (x, ((l, r), i)) =
(if i mod 2 = 0 then (x :: l, r) else (l, x :: r), i + 1)
val (l, r) =
#1 (List.foldl choose (([], []), 0) xs)
in
(List.rev l, List.rev r)
end
I build up the list partitions backwards and then reverse at the end to avoid quadratic blowup of appending to the end for every element. If you wish to have the length of 8 constraint, then you can combine the usage of the above function with List.take from the basis library.
#contificate has offered a good explanation.
If you're implementing a list partitioning function.
There's no reason not to factor out the function that will decide how to partition the list. This function only needs to take in a value and return a boolean value.
This is easily implemented in terms of a fold. There is no need, from what I can see, to keep track of the index.
fun partition f lst =
let
val (a, b) = List.foldl (fn (x, (a, b)) => if f x then (x::a, b) else (a, x::b)) ([], []) lst
in
(List.rev a, List.rev b)
end;
partition (fn x => x mod 2 = 0) [1, 2, 3, 4, 5];
Yields:
([2, 4], [1, 3, 5])
If you simply want to split based on index
If we're aiming to split a list into two lists based on the index:
[4, 7, 1, 9, 8]
Becomes:
([4, 1, 8], [7, 9])
That can be done entirely functionally as well with simple pattern matching and recursion.
let rec split lst (acc1, acc2) =
match lst with
| [] -> (acc1, acc2)
...
Here we're passing in the list to split, and an accumulator with the two lists. Obviously, if the list is empty, the result is just the accumulator. What if there's one element in the list?
let rec split lst (acc1, acc2) =
match lst with
| [] -> (acc1, acc2)
| [x] -> (x::acc1, acc2)
...
Well, that goes in the first list. What if there are more elements than one?
let rec split lst (acc1, acc2) =
match lst with
| [] -> (acc1, acc2)
| [x] -> (x::acc1, acc2)
| x::y::tail -> split tail (x::acc1, y::acc2)
Well, then we match the first two elements and the tail. We update the accumulator to place the first two elements in their respective lists, and call split again with the tail and that updated accumulator.
utop # split [4; 7; 1; 9; 8] ([], []);;
- : int list * int list = ([8; 1; 4], [9; 7])
Oops. They're backwards because of how we constructed the accumulators. We can use List.rev to fix this, but because we don't want to do it twice, when there's one element we'll call split on an empty list.
let rec split lst (acc1, acc2) =
match lst with
| [] -> (List.rev acc1, List.rev acc2)
| [x] -> split [] (x::acc1, acc2)
| x::y::tail -> split tail (x::acc1, y::acc2)
utop # split [4; 7; 1; 9; 8] ([], []);;
- : int list * int list = ([4; 1; 8], [7; 9])
And finally you can shadow split to remove the need to explicitly pass the tuple of empty lists.
let rec split lst (acc1, acc2) =
match lst with
| [] -> (List.rev acc1, List.rev acc2)
| [x] -> split [] (x::acc1, acc2)
| x::y::tail -> split tail (x::acc1, y::acc2)
let split lst = split lst ([], [])
I'm trying to implement a function called even/2 that takes a list of numbers and returns an equivalent list but one where all even numbers have been doubled. I'm supposed to use the
function rem(n, k) which returns the reminder when dividing n with k.
I understand /2 means takes two arguments.
I tried to solve it by using an anonymous function to check the remainders of each element in the list if it's even, but I don't know how to place it in new list then output it.
One can use rem/2 in guards:
Enum.map(input, fn
even when rem(even, 2) == 0 -> even * 2
odd -> odd
end)
UPDATE/REWRITE: Use this tail recursion
defmodule Main do
def doubleEven( [], output ) do # case of input empty list
Enum.reverse output
end
def doubleEven( [head | tail], output ) do # any other length list
if rem(head, 2) == 0 do
doubleEven(tail, [head*2 | output])
else
doubleEven(tail, [head | output])
end
end
end
Which get called using:
Main.doubleEven( [1,2,3,4,5,6,7,8,9], [] )
and outputs
[1, 4, 3, 8, 5, 12, 7, 16, 9]
Here you go best implementation you can find :P
def double_even([]) do [] end
def double_even([h|t]) do
case rem(h,2) do
0 ->
[h*2|double_even(t)]
_ ->
[h|double_even(t)]
end
end
def even([], acc), do: Enum.reverse(acc)
def even([h|t], acc) when rem(h,2) == 0, do: even(t, [2*h|acc])
def even([h|t], acc), do: even(t, [h|acc])
First, a simple way to do this with one argument:
defmodule Double do
def double([]), do: []
def double([head | tail]) when rem(head, 2) == 0, do: [head * 2 | double(tail)]
def double([head | tail]), do: [head | double(tail)]
end
This uses pattern matching of the argument to assign the first element of the list to the head variable.
when rem(head, 2) == 0 is a guard that means this function clause will only get executed when it is true (the first item of the list is even, in this case).
We then return a new list consisting of the possibly doubled value, and use recursion to compute the rest of the list.
The above method builds up the result in the call stack. I suspect the reason you are asked to use two arguments is to take advantage of tail-call optimisation, which means even though a recursive call it made, no extra stack frames are used. Because we don't have a call stack in which to build the result, we add an extra output argument and build it there:
defmodule Double do
def double([], output), do: Enum.reverse(output)
def double([head | tail], output) when rem(head, 2) == 0, do: double(tail, [head * 2 | output])
def double([head | tail], output), do: double(tail, [head | output])
end
Here we write a function that takes an input and an output list.
The function calls itself until the input has been exhausted (is the empty list []), and builds up the answer in the output list, which it eventually returns. In each call, we prepend the current item to the output list.
iex> Double.double([1,2,3,4], [])
[1, 4, 3, 8]
I have been working on a separate function that returns a list that inserts element x after each k elements of list l (counting from
the end of the list). For example, separate (1, 0, [1,2,3,4]) should return [1,0,2,0,3,0,4]. I finished the function and have it working as follows:
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
let
fun kinsert [] _ = []
| kinsert ls 0 = x::(kinsert ls k)
| kinsert (l::ls) i = l::(kinsert ls (i-1))
in
List.rev (kinsert (List.rev l) k)
end
Im now trying to simplify the function using foldl/foldr without any recursion, but I cant seem to get it working right. Any tips/suggestions on how to approach this? Thank You!
These are more or less the thoughts I had when trying to write the function using foldl/foldr:
foldl/foldr abstracts away the list recursion from the logic that composes the end result.
Start by sketching out a function that has a much similar structure to your original program, but where foldr is used and kinsert instead of being a recursive function is the function given to foldr:
fun separate (k, x, L) =
let fun kinsert (y, ys) = ...
in foldr kinsert [] L
end
This isn't strictly necessary; kinsert might as well be anonymous.
You're using an inner helper function kinsert because you need a copy of k (i) that you gradually decrement and reset to k every time it reaches 0. So while the list that kinsert spits out is equivalent to the fold's accumulated variable, i is temporarily accumulated (and occasionally reset) in much the same way.
Change kinsert's accumulating variable to make room for i:
fun separate (k, x, L) =
let fun kinsert (y, (i, xs)) = ...
in foldr kinsert (?, []) L
end
Now the result of the fold becomes 'a * 'a list, which causes two problems: 1) We only really wanted to accumulate i temporarily, but it's part of the final result. This can be circumvented by discarding it using #2 (foldr ...). 2) If the result is now a tuple, I'm not sure what to put as the first i in place of ?.
Since kinsert is a separate function declaration, you can use pattern matching and multiple function bodies:
fun separate (k, x, L) =
let fun kinsert (y, (0, ys)) = ...
| kinsert (y, (i, ys)) = ...
in ... foldr kinsert ... L
end
Your original kinsert deviates from the recursion pattern that a fold performs in one way: In the middle pattern, when i matches 0, you're not chopping an element off ls, which a fold would otherwise force you to. So your 0 case will look slightly different from the original; you'll probably run into an off-by-one error.
Remember that foldr actually visits the last element in the list first, at which point i will have its initial value, where with the original kinsert, the initial value for i will be when you're at the first element.
Depending on whether you use foldl or foldr you'll run into different problems: foldl will reverse your list, but address items in the right order. foldr will keep the list order correct, but create a different result when k does not divide the length of L...
At this point, consider using foldl and reverse the list instead:
fun separate (k, x, L) =
let fun kinsert (y, (?, ys)) = ...
| kinsert (y, (i, ys)) = ...
in rev (... foldl kinsert ... L)
end
Otherwise you'll start to notice that separate (2, 0, [1,2,3,4,5]) should probably give [1,2,0,3,4,0,5] and not [1,0,2,3,0,5].
fun p(L) =
[L] # p( tl(L) # [hd(L)] );
If L is [1,2,3] then I want to have a [ [1,2,3], [2,3,1], [3,1,2] ].
Since every time I append the first num to the end, then if L = [] then [] doesn't work here.
How to stop the function once it has the three lists?
You can have a parameter x in the function to keep track of how many levels deep in the recursion you are.
fun p(L, x) =
if x < length(L) then [L] # p(tl(L) # [hd(L)], x+1)
else [];
Then call the function with x=0.
p([1, 2, 3], 0)
And if you don't like the extra parameter, then as you probably know you can define another function and make it equal to the p function with the parameter forced to 0.
fun p0(L) = p(L, 0);
p0([1, 2, 3]); (* same result as p([1, 2, 3], 0); *)
Let me show some more implementation variants.
First of all, let's define an auxiliary function, which rotates a list 1 position to the left:
(* operates on non-empty lists only *)
fun rot1_left (h :: tl) = tl # [h]
Then the p function could be defined as follows:
fun p xs =
let
(* returns reversed result *)
fun loop [] _ _ = []
| loop xs n res =
if n = 0
then res
else loop (rot1_left xs) (n-1) (xs :: res)
in
List.rev (loop xs (length xs) [])
end
It's usually better (performance-wise) to add new elements at the beginning of the list and then reverse the resulting list once, than to append to the end many times. Note: this version does one spurious rotate at the end and I could have optimized it out, but didn't, to make code more clear.
We have calculated the length of the given list to make its rotated "copies", but we don't have to traverse xs beforehand, we can do it as we rotate it. So, we can use xs as a kind of counter, recursively calling the loop helper function on the tail of the xs list.
fun p xs =
let
(* returns reversed result *)
fun loop [] _ _ = []
| loop xs [] res = res
| loop xs (_::tl) res =
loop (rot1_left xs) tl (xs :: res)
in
List.rev (loop xs xs [])
end
Having done that, we are now closer to implementing p as a foldl function:
fun p xs =
(List.rev o #1)
(List.foldl
(fn (_, (res, rot)) => (rot::res, rot1_left rot))
([], xs)
xs)
The second argument to the List.foldl function is our "accumulator", which is represented here as a pair of the current (partial) result as in the previous implementations and the current rotated list. That explains (List.rev o #1) part: we need to take the first component of the accumulator and reverse it. And as for the ([], xs) part -- the current result is empty at the beginning (hence []) and we start rotating the initial xs list. Also, the _ in (_, (res, rot)) means the current element of the given xs, which we don't care about, since it just serves as a counter (see the prev. variant).
Note: o stands for function composition in Standard ML.
I want to be able to loop every second element of a given list. I can do this recursively as so:
check validate (x:xs) = check (validate x) (tail xs)
But the problem is that I need a function that accepts a list as parameter, then returns a list consisting of only every second element in the list, starting with (and including) the first element of the list, and I do not think this is possible recursively.
Can someone show me how to this using list comprehension? This would probably be the best approach.
second (x:y:xs) = y : second xs;
second _ = []
List comprehension may not be useful.
You can also try mutual recursion
first [] = []
first (x:xs) = x:second xs
second [] = []
second (x:xs) = first xs
such as
> first [1..10]
[1,3,5,7,9]
> second [1..10]
[2,4,6,8,10]
One of the Haskellish approaches would be something with map, filter, and zip.
second xs = map fst $ filter (odd . snd) $ zip xs [1..]
If you really wanted to use list comprehension, you could use the parallel list comprehension extension.
{-# LANGUAGE ParallelListComp #-}
second xs = [ x | (x, n) <- [ (x, n) | x <- xs | n <- [1..] ], odd n ]
I think that the former is concise, though.