Problems understanding sequential Erlang - erlang

I have been examining a code example and I cannot understand what is happening, I have tried to understand easier examples and get them but at this one I am getting stuck:
seq([X, X | Xs]) -> [X | seq(Xs)];
seq([X, Y | Xs]) -> [X, Y | seq(Xs)];
seq(_) -> [].
When I run it in the shell with [1,1,1,2,2,2,3] I get [1,1,2,2]. I have been trying to understand the steps by writing it on paper but I got stuck halfway trough.
I would appreciate all answers explaining me the steps happening here! :)
/Eri.

Ok, so we start with a list of [1,1,1,2,2,2,3].
On the first call to seq, erlang will match the first two elements 1 and 1 to the first "clause" of seq - seq([X, X | Xs]).
This will initialize the list that will become the final return value, [1, seq(Xs)]. Now at this point Xs will be bound to the value [1,2,2,2,3]. If you're wondering why there aren't two 1's at the beginning of the Xs list it's because we matched/bound two of them on [X, X | Xs].
Return value = [1 | ?] (? is the remaining recursion to be evaluated)
Xs = [1,2,2,2,3]
On the second call to seq, erlang will match the first two elements of the input list 1 and 2 to the second clause seq([X, Y | Xs]). We then "return" the list [X, Y] or [1, 2] from this run, and call the next iteration with Xs = [2,2,3].
Return value = [1 | [1, 2 | ?]] <- See how recursion nests the lists?
Xs = [2,2,3]
On the third call, the first two elements are the same again, so erlang runs the first clause again. seq([X, X | Xs]) -> [X | seq(Xs)]. We return a single 2 value as part of the evaluation, and call seq([3]).
Return value = [1 | [1, 2 | [2 | ?]]]
Xs = [3]
At last, the final case. Our list of [3] doesn't match [X, X | Xs] nor [X, Y, Xs], so erlang will run our catch-all: seq(_) -> []. _ will match anything, and not bind the value to any local variables, so all we do here is return an empty list [].
Our final return value then is: [1 | [1, 2 | [2 | []]]]. If you evaluate this into your erl repl, you'll see it's the same as the list [1,1,2,2], the later is syntactic sugar for the former.

Tracing can help you a little bit:
1> dbg:tracer().
{ok,<0.35.0>}
2> dbg:p(self(), [c]).
{ok,[{matched,nonode#nohost,1}]}
3> dbg:tpl({test, seq, 1}, [{'_',[],[{return_trace}]}]).
{ok,[{matched,nonode#nohost,1},{saved,1}]}
4> test:seq([1, 1, 1, 2, 2, 2, 3]).
(<0.33.0>) call test:seq([1,1,1,2,2,2,3])
(<0.33.0>) call test:seq([1,2,2,2,3])
(<0.33.0>) call test:seq([2,2,3])
(<0.33.0>) call test:seq([3])
(<0.33.0>) returned from test:seq/1 -> []
(<0.33.0>) returned from test:seq/1 -> [2]
(<0.33.0>) returned from test:seq/1 -> [1,2,2]
(<0.33.0>) returned from test:seq/1 -> [1,1,2,2]
[1,1,2,2]

Related

How to evaluate the first element of a tuple ONLY if elements in the tuple are identical in Erlang?

Let's say our Variable Five is a tuple of five elements.
How do we write an expression that evaluates to (and prints) the first element, but only if all five elements are identical?
For example, given this following tuple:
Five = {4, 4, 4, 4, 4}.
I'm trying to use element(_,_). Statement as:
element(1, Five) =:= element(2, Five).
But this only give me the evaluation of the first element VS the 2nd one, not all together.
Any idea how I can evaluate the first one with all the other elements the same time?
{ .................. } = Five, ....................
If you know the size of the tuple (e.g. 5 as in your example), you could pattern match using the same variable:
case Five of
{X, X, X, X, X} -> io:format("~w", [X]), X;
_Otherwise -> ok
end
Of course, the same can be done in function clauses.
If the size of the tuple is unknown, one way would be to convert it to a list using tuple_to_list/1 and, for example, use lists:all/2:
[H | T] = tuple_to_list(Five),
IsSame = lists:all(fun (E) -> E =:= H end, T),
case IsSame of
true -> io:format("~w", [H]), H;
false -> ok
end

How to use whole list function argument in Erlang

I can understand most of the [H|T] examples I read in the docs. I usually means that I want to use either the H or the T part of the list. What if I want to use the whole list instead. Sample code:
-module(module_variable).
-export([main/0, list_suffix/1]).
variable() -> [1, 2, 3, 4, 5].
list_suffix([_H|T]) ->
lists:suffix(variable, T).
main() ->
io:fwrite("~p~n", [list_suffix([4, 5])]).
The error I get is:
6> module_variable:list_suffix([1,[4, 5]]).
** exception error: bad argument
in function length/1
called as length(variable)
in call from lists:suffix/2 (lists.erl, line 205)
Help is appreciated.
You can use multiple values from the front of the list. You cannot skip an arbitrary number of values in the middle. Since in your code you don't know how many elements from the head you want to match ahead of time, pattern matching can't do this for you.
Some examples:
Setup:
1> A = [1, 2, 3, 4, 5].
[1,2,3,4,5]
Matches first 2 elements of list
2> [1, 2 | _ ] = A.
[1,2,3,4,5]
% Can pattern match to extract values
3> [B, C | _ ] = A.
[1,2,3,4,5]
4> B.
1
5> C.
2
Can match some constant values and also assign
6> [1, 2, D | _ ] = A.
[1,2,3,4,5]
Can match whole list
7> [1, 2, 3, 4, 5] = A.
[1,2,3,4,5]
% Can't skip over elements in the middle
8> [1, 2| [4, 5]] = A.
** exception error: no match of right hand side value [1,2,3,4,5]
% This works, though not useful most of the time:
9> [1, 2, 3 | [4, 5]] = A.
[1,2,3,4,5]
% Can assign every element
10> [B, C, D, E, F] = A.
[1,2,3,4,5]
11> E.
4
12> F.
5
% If you don't use a pipe, the length has to match exactly
13> [B, C, D, E] = A.
** exception error: no match of right hand side value [1,2,3,4,5]

Erlang: do list comprehension filters short circuit

Lets say I have:
[ X || X<- L, some_expensive_boolean(X), some_expensive_boolean2(X)]
If, for any X in L, some_expensive_boolean(X) is false, is some_expensive_boolean2(X) executed?
TL;DR: No, some_expensive_boolean2/1 is not called.
There a couple of ways you can verify this.
1. Having functions print something as they are called.
-module(lc).
-export([lc/1]).
lc(L) ->
[X || X <- L, f(X), g(X)].
f(X = 2) ->
erlang:display({f, 2}),
false;
f(X) ->
erlang:display({f, X}),
true.
g(X) ->
erlang:display({g, X}),
true.
Then on the Erlang shell:
1> lc:lc(lists:seq(1, 4)).
{f,1}
{g,1}
{f,2} %% g is not called here
{f,3}
{g,3}
{f,4}
{g,4}
[1,3,4]
2. Check the generated Core Erlang code.
Compiling the module with the +to_core option will produce a lc.core file with the Core Erlang code, which looks a little bit like Erlang but has its own syntax but very similar semantics.
erlc +to_core lc.erl
The code generated is quite verbose so I won't paste it here, but the gist is that there are two nested case expressions, one calling f/1 with the clause that matches on true containing the other case that calls g/1.
The answer is no. It is short-circuited.
1> [ X || X <-[1,2], begin io:format("Test 1: ~p~n", [X]), X rem 2 =:= 0 end, io:format("Test 2: ~p~n", [X]) =:= ok ].
Test 1: 1
Test 1: 2
Test 2: 2
[2]
Short-circuits based on the following:
-module(shortcircuit).
-export([test/0]).
test() ->
L = [1, 2, 3],
[ X || X <- L, some_expensive_boolean(X), some_expensive_boolean2(X)].
some_expensive_boolean(X) ->
io:format("In some_expensive_boolean: ~p~n", [X]),
false.
some_expensive_boolean2(X) ->
io:format("In some_expensive_boolean2: ~p~n", [X]),
true.
Execute:
1> shortcircuit:test().
In some_expensive_boolean: 1
In some_expensive_boolean: 2
In some_expensive_boolean: 3
[]
2>
Let's create an example:
$ cat test.erl
-module(test).
-export([show/0]).
show() ->
[ X || X <- [1,2,3,4,5], bigger(X), smaller(X)].
bigger(X) ->
io:format("bigger ~p~n", [X]),
X > 2.
smaller(X) ->
io:format("smaller ~p~n", [X]),
X < 4.
and test it:
14> c(test).
{ok,test}
15> test:show().
bigger 1
bigger 2
bigger 3
smaller 3
bigger 4
smaller 4
bigger 5
smaller 5
[3]
So the answer is: NO.

How do you use foldl in erlang on a list of integers to return the maximum integer?

I would like to use the below Erlang code to get the highest integer in a list of integers but for some reason always end up getting the last integer in the list. Any help?
Solution example -> test:max([2,8,5,6]). should return 8 but with this code it returns 6.
-spec max(L) -> M when
L::[integer()],
M::integer().
max([H | T]) ->
F = fun(L, Acc) -> max([L]) end,
lists:foldl(F, H, T).
Your function F should return the max of L and Acc. You can use the builtin max/2 function for that:
...
F = fun(L, Acc) -> max(L, Acc) end.
...
Test:
1> F = fun(L, Acc) -> max(L, Acc) end.
#Fun<erl_eval.12.52032458>
2> [H | T] = [2, 8, 5, 6].
[2,8,5,6]
3> lists:foldl(F, H, T).
8
What you return in your function F will be the new value of Acc, and eventually the value lists:foldl/3 will return.
What you may want to do is do comparison inside F and check if Acc is greater than the current value. You don't need to recurse max/1 since you're iterating the list in lists:foldl/3 anyway.
Let me know if you need the actual code right away, but I would recommend figuring it out yourself. It's more fun for you that way.

what is wrong with my unpair implementation?

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 ]

Resources