This question already has answers here:
Elixir list concatenation
(2 answers)
Closed 1 year ago.
How to do nil safe concatenation of lists in Elixir?
I have presented few inline examples of the situation and response with ++
Looks like nil is treated as a special entity when concatenating.
Why does this happen?
# Append two empty list ✅
iex(1)> [] ++ []
[]
# Append empty list to nil ❌
iex(2)> [] ++ nil
nil # Result should be []
# Append non empty list to nil ❌
iex(3)> [1] ++ nil
[1 | nil] # Result should be [1]
# Append non empty list to nil and enumerate ❌
iex(5)> a = [1, 2] ++ nil
[1, 2 | nil]
iex(6)> Enum.each(a, fn p -> IO.puts(p) end)
1
2
** (FunctionClauseError) no function clause matching in Enum."-each/2-lists^foreach/1-0-"/2
# Add more lists with nil ❌
iex(5)> [1, 2] ++ nil ++ []
** (ArgumentError) argument error
I believe you want to get back a normal, proper list. For that both arguments in a call to ++/2 must be lists.
You are probably after List.wrap/1 for nil.
iex|1 ▸ [] ++ List.wrap([])
#⇒ []
iex|2 ▸ [] ++ List.wrap(nil)
#⇒ []
iex|3 ▸ [1] ++ List.wrap(nil)
#⇒ [1]
iex|4 ▸ [1, 2] ++ List.wrap(nil)
#⇒ [1, 2]
iex|5 ▸ [1, 2] ++ List.wrap(nil) ++ [3]
#⇒ [1, 2, 3]
iex|6 ▸ [1] ++ List.wrap(2)
#⇒ [1, 2]
You have discovered improper lists: a list where the tail of the last element is not an empy list. There's a nice example in the List documentation:
Regular list (equivalent to [1, 2, 3]):
[1 | [2 | [3 | []]]]
Improper list (equivalent to [1, 2 | 3]):
[1 | [2 | 3]]
There's nothing special about nil - the same thing happens for any non-list:
iex(1)> [1, 2] ++ "foo"
[1, 2 | "foo"]
iex(2)> [1, 2] ++ %{3 => 4}
[1, 2 | %{3 => 4}]
iex(3)> Enum.each([1,2|"boom"], &IO.puts(&1))
1
2
** (FunctionClauseError) no function clause matching in Enum."-each/2-lists^foreach/1-0-"/
From the documentation for ++:
List concatenation operator. Concatenates a proper list and a term,
returning a list.
If the right operand is not a proper list, it returns an improper
list. If the left operand is not a proper list, it raises
ArgumentError.
The error from Enum.each is strange, but it seems to be caused by the implementation of expecting a proper list, too.
I think this answers your question, but I suspect it doesn't solve your problem. You didn't mention why you are appending nil to lists, nor what you are trying to achieve.
If you want to eliminate the nil part then you can use pattern matching for it. eg:
defmodule Example do
def add(list1, list2) do
case [list1, list2] do
[nil, nil] -> []
[nil, list2] -> list2
[list1, nil] -> list1
[list1, list2] -> list1 ++ list2
end
end
end
Related
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
fun map f nil = nil
| map f (hd::tl) = f(hd) :: map f tl;
fun everywhere e nil = [[e]]
| everywhere e (y::ys) =
(e::y::ys) :: (map (fn u => y::ys) (everywhere e ys));
I don't know how those sml codes work.
I know map function.
But about everywhere code, I don't know how much I think about that.
Please let me know
Thank you
First, I guess "everywhere" should be fixed to get the behavior expected from its name:
fun everywhere e nil = [[e]]
| everywhere e (y::ys) =
(e::y::ys) :: (map (fn u => y::u) (everywhere e ys));
This modified version provides a list of list. For example,
- everywhere 4 [1,2,3] ;
val it = [[4,1,2,3],[1,4,2,3],[1,2,4,3],[1,2,3,4]] : int list list
So, You may know that "everywhere e xs" enumerates all possible lists which are made by inserting item "e" into somewhere of the original list xs.
Then, how can you enumerate the insertion? It is divided into two cases:
insert at the top: [1,2,3] -> [4, 1,2,3]
insert between the first and the second or later: [1, 4 ,2,3], [1,2, 4 ,3],...
Case 1 is realized by just (e::y::ys).
Case 2 is further split into two steps:
A) get all possibilities of insertion of "e" to the sub list "ys" of the second and the following items: [4, 2, 3], [2, 4, 3], ...
B) add the first item "y" of the original list into EACH of the outcome of step A:
1 :: [4,2,3], 1::[2,4,3], ...
Step 2A can be done by calling "everywhere" itself with the sub list as an argument. Then, appending item "y" into each of (everywhere e ys), you have done Step 2B.
For this (doing the same thing for items), you can use "map".
I have just started learning Haskell and I am trying to write some basic functions in order to get a better understanding of this language.
I want to write a function which takes a list and an Int (N) as argument and returns the element at index N in the list, without using the !! operator or any built-in function.
Here is what I tried :
myHead :: [a] -> a
myHead (x:_) = x
myHead [] = error "head: empty list"
myNth :: [a] -> Int -> a
myNth x i = if i < 0
then error "nth: index can't be negative"
else myNthIterator x i 0
myNthIterator :: [a] -> Int -> Int -> a
myNthIterator [] i n = error "nth: bad index"
myNthIterator (_:x) i n = if i == n
then myHead x
else myNthIterator x i ( n + 1 )
It works but it's shifted to the right. For example myNth [1, 2, 3, 4] 2 would give 4 and not 3.
From what I understand, (_:x) removes the first element of the list and I don't see how to iterate through the list element by element.
Could someone put me on the trail? I find it difficult to find resources for beginners in this language.
We can use Maybe to model whether the index was valid.
nth :: Int -> [a] -> Maybe a
nth 0 (x : _) = Just x
nth n (x : xs) = nth (n - 1) xs
nth _ [] = Nothing
We can pattern match on the index to get our base case, and the list to get the first element and tail.
What you're doing there with (_:x) is called "pattern matching" in case you didn't know. The general pattern for iterating through a list would be (x : xs) where x is head element of the list being matched and xs is the rest of the list. If you use _ you don't remove anything it is still matched to _ which is the convention for saying "I won't use this".
With that you can make a function like this:
myNth :: [a] -> Int -> a
myNth [] _ = error "out of range"
myNth (x : xs) 0 = x
myNth (_ : xs) n = myNth xs (n - 1)
Whenever myNth is called it will go top to bottom over those definitions trying to match the patterns to the input. So when you call myNth [10,11] 1 it won't match the first clause because [10,11] doesn't match an empty list, it won't match the second either because 1 is not 0 and so it will match the third case where it will match the [10,11] on (10 : [11]), therefore _ is 10 and xs is [11] and 1 will be matched as n. Then it calls itself recursively, as myNth [11] 0. Now that will match the second case and it will return x from the match of [11] on (11 : [])
Like 414owen said you can use the Maybe a type to avoid using error.
P.S.: I don't know how beginner you are but I assume you know of the : operator, it prepends an element to a list... If you go more in depth (afaik) every list is actually stored as a sequence of a:(b:(c:(d:(e:[])))) which is equivalent to [a,b,c,d,e] which is equivalent to a:[b,c,d,e] etc.
It works but it's shifted to the right. For example myNth [1, 2, 3, 4] 2 would give 4 and not 3.
myNthIterator (_:x) i n = if i == n
then myHead x
else myNthIterator x i ( n + 1 )
Let us look at myNthIterator [1..4] 1 1
myNthIterator [1..4] 1 1 -- replace [a, b] with (a: (b : []))
== myNthIterator (1 : [2, 3, 4]) 1 1
-- matching with `myNthIterator (_:x) i n` will result in
-- 1 ~ _
-- x ~ [2, 3, 4]
-- i ~ 1
-- n ~ 1
== if 1 == 1 then myHead [2, 3, 4] else myNthIterator [2, 3, 4] 1 (1 + 1)
== myHead [2, 3, 4]
== 2
So (_:x) matching against (1 : [2, 3, 4]) is suspicious. A first step in fixing it is to replace (_:x) by (x:xs).
myNthIterator (x:xs) i n = ...
In our example this would mean x == 1 and xs == [2, 3, 4].
I have a question regarding the execution flow in recursive functions in OCaml. This is scenario:
I have two recursive functions, Concat and Reverse. Reverse calls Concat. Would anyone be able to explain what happens when I, for example, submits the list [1; 2; 3]?
let rec concat (l1,l2) =
match l1 with
[] -> l2
| (h::t) -> h::(concat (t,l2));;
let rec reverse (l: int list) =
match l with
[] -> []
| (h :: t) -> concat (reverse t, [h]);;
// Call
let list1 = [1; 2; 3] ;;
reverse list1 ;;
I know this is not the optimal way to reverse a list, but right now I only interested in how two recursive functions work with each other.
Thanks!
If you annotate concat as taking two lists of ints:
let rec concat (l1, l2 : int list * int list) =
. . .
You can ask the toplevel (OCaml REPL) to trace the function calls and return values. This might tell you exactly what you want to know.
$ rlwrap ocaml
OCaml version 4.06.1
. . .
# trace concat;;
concat is now traced.
# trace reverse;;
reverse is now traced.
# reverse [1; 2; 3];;
reverse <-- [1; 2; 3]
reverse <-- [2; 3]
reverse <-- [3]
reverse <-- []
reverse --> []
concat <-- ([], [3])
concat --> [3]
reverse --> [3]
concat <-- ([3], [2])
concat <-- ([], [2])
concat --> [2]
concat --> [3; 2]
reverse --> [3; 2]
concat <-- ([3; 2], [1])
concat <-- ([2], [1])
concat <-- ([], [1])
concat --> [1]
concat --> [2; 1]
concat --> [3; 2; 1]
reverse --> [3; 2; 1]
- : int list = [3; 2; 1]
Functions, recursive or not, are evaluated by first evaluating all it's arguments in an unspecified order and then calling the function with them.
So for example concat (reverse t, [h]) will first evaluate reverse and then call concat.
I'm a Haskell beginner,
I have a function
func :: Num a => [a] -> [a]
func [] = []
func (x:xs) = x + func xs
Each recursion I want to append the value to a list for my output. This function will sum consecutive indexes in a list so that the input [1, 2, 3, 4] produces [1, 3, 6, 10].
How do I append the value generated each time to my list?
Your problem here isn't how to append, but rather how to calculate the value in the first place. Each item needs to be substituted with a sum of itself with all the items preceding it.
Here is one way to do it:
Prelude> func (x:xs) = x:map (+ x) (func xs); func [] = []
Prelude> func [1, 2, 3, 4]
[1,3,6,10]
How does this work? We're given a list that starts with the element x and has the remaining elements xs. We want to increment every item in xs by x, after recursively applying the algorithm to xs.
This is what x:map (+ x) (func xs) does. It reads as "prepend x to the result of mapping every element in func xs through an increment by x".
E.g. for [1, 2, 3, 4], we want 1 to be added to every member of the result of recursively applying the algorithm to [2, 3, 4], then prepended. For [2, 3, 4] we want 2 to be ... to [3, 4]. And so on, until eventually for [4] we want 4 to be added and prepended to the result of applying the algorithm to [].
This is where our base case (func [] = []) kicks in: the algorithm is defined so that it returns an empty list unchanged. Hence func [4] is [4], func [3, 4] is [3, 7], and you keep incrementing and prepending until you get [1,3,6,10].
I think in this particular case, you could use scanl1 like:
scanl1 (+) [1,2,3,4] -- [1,3,6,10]
When iterating over lists, we often use folds, which is a way of reducing the list to a particular value.
There's also another type of operation, which is a fold that collects all results along the way, and that's called a scan (from the docs):
scanl = scanlGo
where
scanlGo :: (b -> a -> b) -> b -> [a] -> [b]
scanlGo f q ls = q : (case ls of
[] -> []
x:xs -> scanlGo f (f q x) xs)
So the scan takes three arguments: a function that takes two values and returns a value, a starter value, and a list of values.
The scan will then return a list.
Thus, what you need is a function that takes two values and returns something of the same type as the first (it's okay if both are the same). Binary addition would work here: +.
You also need a value to start off with (the b, which is the second argument to our function), and 0 is the identity for integer addition, so we should use that.
Finally, we pass your list to get the result.
Try to figure out how to write you function as a fold and then as a scan and you will discover the answer.