What does the "head mismatch" compiler error mean? - erlang

I tries to write code to print Z character.
zzzzzzz
z
z
z
z
z
zzzzzzz
But when I compile this code, it throws
D:\erlang\graphics>erlc zeez2.erl
d:/erlang/graphics/zeez2.erl:19: head mismatch
d:/erlang/graphics/zeez2.erl:6: function zeez/3 undefined
I can't fixed this error. I didn't find what wrong in my could.
Does one please suggest me.
Thank you.
-module(zeez2).
-export([main/0]).
main() ->
L = 8,
zeez( false ,1, L). % line 6
zeez(true, M,M) ->
init:stop();
zeez(false, M, N) ->
io:format("~p~n", [zeez(z, N-M)] ),
zeez(M rem N =:= 0, M + 1, N );
zeez(true, M, N) ->
io:format("~p~n", [zeez(space, N-M)] ), % line 16
zeez(M rem N =:= 0, M + 1 , N );
zeez(space, M) ->
io:format("~p~n", ["-" ++ zeez(space, M-1)] );
zeez(space, 0) ->
"Z";
zeez(z, M) ->
io:format("~p~n", ["Z" ++ zeez(z, M-1)] );
zeez(z,0) ->
"Z".

the problem is that you have mixed up 2 functions:
zeez/2 and zeez/3
If you terminate the zeez/3 function by ending it with a full stop not a semi-colon it should compile:
zeez(true, M, N) ->
io:format("~p~n", [zeez(space, N-M)] ), % line 16
zeez(M rem N =:= 0, M + 1 , N ); <-- should end with .
The error message means, 'hey I'm in zeez/3 and you have thrown in a 2-arity clause, wtf?'

You're trying to define two functions, the first with 3 parameters (zeez/3) and another with 2 parameters (zeez/2). The head mismatch error is because the zeez/3 function on the previous line should be terminated with a '.'.
I.e. because you've ended the previous zeez/3 function with a ';', it expects the following declaration to be another match for zeez/3:
zeez(true, M, N) ->
io:format("~p~n", [zeez(space, N-M)] ), % line 16
zeez(M rem N =:= 0, M + 1 , N ).
zeez(space, M) ->
io:format("~p~n", ["-" ++ zeez(space, M-1)] );
You should also note that the compiler will give you warnings about "... previous clause at line xxx always matches" because of the ordering of zees(space, 0) and zeez(space, M). You should put zees(space, 0) before zeez(space, M), because it is more specific.

Related

Optimizing max Collatz sequence

I'm looking to optimize my solution for the maximum Collatz sequence problem in Erlang. Right now I've tried using ETS, and the following solution uses maps, but I'm getting worse performance than I feel I should. Is there perhaps some optimization I could do to improve it?
-module(collatzMaps).
-export([start/2, s/4]).
collatz(0, Map) ->
{0, Map};
collatz(M, Map) ->
Exists = maps:is_key(M, Map),
case Exists of
false ->
case M rem 2 == 0 of
true ->
Result = collatz(M div 2, Map),
Val = (1 + element(1, Result)),
Map1 = maps:put(M, Val, element(2, Result)),
{maps:get(M, Map1), Map1};
false ->
Result = collatz((3 * M + 1), Map),
Val = (1 + element(1, Result)),
Map2 = maps:put(M, Val, element(2, Result)),
{maps:get(M, Map2), Map2}
end;
true ->
{maps:get(M, Map), Map}
end.
s(N, M, Max, Map) ->
if
N =< M ->
Result = collatz(N, Map),
if
element(1, Result) > Max ->
NextMax = element(1, Result),
MapNext = element(2, Result),
s(N + 1, M, NextMax, MapNext);
true ->
MapNext = element(2, Result),
s(N + 1, M, Max, MapNext)
end;
true ->
Max
end.
start(N, M)->
statistics(runtime),
statistics(wall_clock),
Map = maps:new(),
Map1 = maps:put(1, 1, Map),
G = s(N, M, 0, Map1),
{_, Time2} = statistics(wall_clock),
U2 = Time2 / 1000,
io:format("~p seconds~n", [U2]),
G.
Well, first let's tweak up invocation which will allow us to make some simple statistics and compare different approaches
-export([start/2, max_collatz/2]).
...
max_collatz(N, M) ->
Map = maps:new(),
Map1 = maps:put(1, 1, Map),
s(N, M, 0, Map1).
start(N, M)->
{T, Result} = timer:tc( fun() -> max_collatz(N, M) end),
io:format("~p seconds~n", [T / 1000000]),
Result.
So let's write it more Erlang idiomatic way
-module(collatz).
-export([start/2, max_collatz/2]).
collatz_next(N) when N rem 2 =:= 0 ->
N div 2;
collatz_next(N) ->
3 * N + 1.
collatz_length(N, Map) ->
case Map of
#{N := L} -> {L, Map};
_ ->
{L, Map2} = collatz_length(collatz_next(N), Map),
{L + 1, Map2#{N => L + 1}}
end.
max_collatz(N, M) ->
Map = lists:foldl(fun(X, Map) -> {_, Map2} = collatz_length(X, Map), Map2 end,
#{1 => 1}, lists:seq(N, M)),
lists:max(maps:values(Map)).
start(N, M) ->
{T, Result} = timer:tc(fun() -> max_collatz(N, M) end),
io:format("~p seconds~n", [T / 1000000]),
Result.
Then we can compare speed using for example eministat.
Clone in
git clone https://github.com/jlouis/eministat.git
cd eministat
make
If you run in a problem like
DEPEND eministat.d
ERLC eministat.erl eministat_analysis.erl eministat_ds.erl eministat_plot.erl eministat_report.erl eministat_resample.erl eministat_ts.erl
compile: warnings being treated as errors
src/eministat_resample.erl:8: export_all flag enabled - all functions will be exported
erlang.mk:4940: recipe for target 'ebin/eministat.app' failed
make[1]: *** [ebin/eministat.app] Error 1
erlang.mk:4758: recipe for target 'app' failed
make: *** [app] Error 2
You can fix it
diff --git src/eministat_resample.erl src/eministat_resample.erl
index 1adf401..0887b2c 100644
--- src/eministat_resample.erl
+++ src/eministat_resample.erl
## -5,7 +5,7 ##
-include("eministat.hrl").
-export([resample/3, bootstrap_bca/3]).
--compile(export_all).
+-compile([nowarn_export_all, export_all]).
%% #doc resample/3 is the main resampler of eministat
%% #end
So then run it
$ erl -pa eministat/ebin/
Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Eshell V10.1 (abort with ^G)
1> c(collatzMaps), c(collatz).
{ok,collatz}
2> eministat:x(95.0, eministat:s(orig, fun() -> collatzMaps:max_collatz(1, 100000) end, 30), eministat:s(new, fun() -> collatz:max_collatz(1, 100000) end, 30)).
x orig
+ new
+--------------------------------------------------------------------------+
|+ ++++++++ +++++ * + +x+**+xxxx**x xxx xx+x xxx *x x + x x|
| + + + x x xx x |
| + |
| |_______M___A__________| |
| |________M_____A______________| |
+--------------------------------------------------------------------------+
Dataset: x N=30 CI=95.0000
Statistic Value [ Bias] (Bootstrapped LB‥UB)
Min: 1.76982e+5
1st Qu. 1.81610e+5
Median: 1.82954e+5
3rd Qu. 1.87030e+5
Max: 1.94944e+5
Average: 1.84280e+5 [ 8.00350] ( 1.82971e+5 ‥ 1.85749e+5)
Std. Dev: 3999.87 [ -102.524] ( 3128.74 ‥ 5431.13)
Outliers: 0/0 = 0 (μ=1.84288e+5, σ=3897.35)
Outlier variance: 3.22222e-2 (slight)
------
Dataset: + N=30 CI=95.0000
Statistic Value [ Bias] (Bootstrapped LB‥UB)
Min: 1.69179e+5
1st Qu. 1.72501e+5
Median: 1.74614e+5
3rd Qu. 1.79850e+5
Max: 1.90638e+5
Average: 1.76517e+5 [ 3.11862] ( 1.74847e+5 ‥ 1.78679e+5)
Std. Dev: 5343.46 [ -147.802] ( 4072.99 ‥ 7072.53)
Outliers: 0/0 = 0 (μ=1.76520e+5, σ=5195.66)
Outlier variance: 9.43164e-2 (slight)
Difference at 95.0% confidence
-7762.60 ± 2439.69
-4.21240% ± 1.32391%
(Student's t, pooled s = 4719.72)
------
ok
So it seems like 4% faster now which is not much. First, we can inline collatz_next/1 which is basically what you have in your collatz/2 function. I like to be specific so I put between -export and a first function
-compile({inline, [collatz_next/1]}).
It have very little effect
Difference at 95.0% confidence
-9895.27 ± 5524.91
-5.24520% ± 2.92860%
(Student's t, pooled s = 1.06882e+4)
Then we can try roll out lists:fold/2, lists:seq/2 and lists:max/1 as in your s/4 function but let's do it more idiomatic way.
max_collatz(N, M) ->
max_collatz(N, M, 1, #{1 => 1}).
max_collatz(M, M, Max, _) -> Max;
max_collatz(N, M, Max, Map) ->
case collatz_length(N + 1, Map) of
{L, Map2} when L > Max ->
max_collatz(N + 1, M, L, Map2);
{_, Map2} ->
max_collatz(N + 1, M, Max, Map2)
end.
Well it's better but still not much
Difference at 95.0% confidence
-1.78775e+4 ± 1980.35
-9.66832% ± 1.07099%
Now, when we removed all external code calls it's worth to try native compiling (external function call usually ruins any native compilation benefit). We could also add little type hint for HiPE but it seems to have barely any effect (it is usually worth to try for floating point arithmetic which is not this case and heavy usage of maps is probably issuing problem here as well).
max_collatz(N, M) when N < M, is_integer(N), is_integer(M) ->
max_collatz(N, M, 1, #{1 => 1}).
Not much better
c(collatz, [native]).
...
Difference at 95.0% confidence
-2.26703e+4 ± 2651.32
-12.1721% ± 1.42354%
(Student's t, pooled s = 5129.13)
So its time try it dirty. Process dictionary is not the recommended place to store your data but if it is inside special process it is an acceptable solution.
collatz_length(N) ->
case get(N) of
undefined ->
L = collatz_length(collatz_next(N)),
put(N, L + 1),
L + 1;
L -> L
end.
max_collatz(N, M) when N < M, is_integer(N), is_integer(M) ->
P = self(),
W = spawn_link(fun() ->
put(1, 1),
P ! {self(), max_collatz(N, M, 1)}
end),
receive {W, Max} -> Max end.
max_collatz(M, M, Max) -> Max;
max_collatz(N, M, Max) ->
case collatz_length(N + 1) of
L when L > Max ->
max_collatz(N + 1, M, L);
_ ->
max_collatz(N + 1, M, Max)
end.
Yes, its dirty but working solution and its worth it (even without native)
Difference at 95.0% confidence
-1.98173e+5 ± 5450.92
-80.9384% ± 2.22628%
(Student's t, pooled s = 1.05451e+4)
So here we are from 3.6s down to 0.93s using some dirty tricks but anyway, if you would do this sort of tasks, you would probably use NIF written in C. It is not a type of task where Erlang shine.
> collatzMaps:start(1, 1000000).
3.576669 seconds
525
> collatz:start(1, 1000000).
0.931186 seconds
525

Erlang sumif function

I'm trying to make a sumif function in Erlang that would return a sum of all elements in a list if the predicate function evaluates to true. Here is what I have:
sumif(_, []) -> undefined;
sumif(Fun, [H|T]) -> case Fun(H) of
true -> H + sumif(Fun, T);
false -> sumif(Fun, T)
end.
I also implemented my own pos function which returns true if a number is greater than 0 and false otherwise:
pos(A) -> A > 0.
I tried using pos with sumif but I'm getting this error:
exception error: bad function pos
Why is this happening? Is it because of my sumif function or pos? I have tested pos on its own and it seems to work just fine.
Edit: It might be because how I'm calling the function. This is how I'm currently calling it: hi:sumif(pos,[-1,1,2,-3]). Where hi is my module name.
Is it because of my sumif function or pos?
It's because of sumif. You should return 0 when an empty list is passed, as it'll be called from the 2nd clause when T is []:
-module(a).
-compile(export_all).
sumif(_, []) -> 0;
sumif(Fun, [H|T]) -> case Fun(H) of
true -> H + sumif(Fun, T);
false -> sumif(Fun, T)
end.
pos(A) -> A > 0.
Test:
1> c(a).
{ok,a}
2> a:sumif(fun a:pos/1, [-4, -2, 0, 2, 4]).
6
List comprehensions make things far simpler:
sumif(F, L) ->
lists:sum([X || X <- L, F(X)]).
Dobert's answer is of cousrse right, problem is your sum for empty list.
If your concern is performance a little bit you should stick to tail recursive solution (in this case it matter because there is not lists:reverse/1 involved).
sumif(F, L) ->
sumif(F, L, 0).
sumif(F, [], Acc) when is_function(F, 1) -> Acc;
sumif(F, [H|T], Acc) ->
New = case F(H) of
true -> H+Acc;
false -> Acc
end,
sumif(F, T, New).
Ways how to make correct function for first parameter:
F1 = fun pos/1, % inside module where pos/1 defined
F2 = fun xyz:pos/1, % exported function from module xyz (hot code swap works)
N = 0,
F3 = fun(X) -> X > N end, % closure
% test it
true = lists:all(fun(F) -> is_function(F, 1) end, [F1, F2, F3]).
There has tow error in your code:
1. sumif(_, []) -> undefined; should return 0, not undefined.
2. when you pass pos(A) -> A > 0. to sumif/2,you should use fun pos/1, please read http://erlang.org/doc/programming_examples/funs.html#id59138
sumif(F, L) ->
lists:foldl(fun(X, Sum) when F(X) -> Sum+X; (_) -> Sum end, 0, L).
You can use lists:foldl.

erlang; outsmarting compiler with memoization?

The following is my solution to Project Euler 14, which works (in 18 s):
%Which starting number, under one million, produces the longest Collartz chain?
-module(soln14).
-export([solve/0]).
collatz(L) ->
[H|T] = L,
F = erlang:get({'collatz', H}),
case is_list(F) of
true ->
R = lists:append(F, T);
false ->
if H == 1 ->
R = L;
true ->
if H rem 2 == 0 ->
R = collatz([H div 2 | L]);
true ->
R = collatz([3*H+1 | L])
end
end,
erlang:put({'collatz', lists:last(L)}, R),
R
end.
dosolve(N, Max, MaxN, TheList) ->
if N == 1000000 -> MaxN;
true ->
L = collatz([N]),
M = length(L),
if M > Max -> dosolve(N+1, M, N, L);
true ->
dosolve(N+1, Max, MaxN, TheList)
end
end.
solve() ->
{Megass, Ss, Micros} = erlang:timestamp(),
S = dosolve(1, -1, 1, []),
{Megase, Se, Microe} = erlang:timestamp(),
{Megase-Megass, Se-Ss, Microe-Micros, S}.
However, the compiler complains:
8> c(soln14).
soln14.erl:20: Warning: variable 'R' is unused
{ok,soln14}
9> soln14:solve().
{0,18,-386776,837799}
Is this a compiler scoping error, or do I have a legit bug?
It's not a compiler error, just a warning that in the true case of "case is_list(F) of", the bindning of R to the result of lists:append() is pointless, since this value of R will not be used after that point, just returned immediately. I'll leave it to you to figure out if that's a bug or not. It may be that you are fooled by your indentation. The lines "erlang:put(...)," and "R" are both still within the "false" case of "case is_list(F) of", and should be deeper indented to reflect this.
The error message and the code are not "synchronized". with the version you give, the warning is on line 10: R = lists:append(F, T);.
What it means is that you bind the result of the lists:append/2 call to R and that you don't use it later in the true statement.
this is not the case in the false statement since you use R in the function erlang:put/2.
You could write the code this way:
%Which starting number, under one million, produces the longest Collartz chain?
-module(soln14).
-export([solve/0,dosolve/4]).
collatz(L) ->
[H|T] = L,
F = erlang:get({'collatz', H}),
case is_list(F) of
true ->
lists:append(F, T);
false ->
R = if H == 1 ->
L;
true ->
if H rem 2 == 0 ->
collatz([H div 2 | L]);
true ->
collatz([3*H+1 | L])
end
end,
erlang:put({'collatz', lists:last(L)}, R),
R
end.
dosolve(N, Max, MaxN, TheList) ->
if N == 1000000 -> MaxN;
true ->
L = collatz([N]),
M = length(L),
if M > Max -> dosolve(N+1, M, N, L);
true ->
dosolve(N+1, Max, MaxN, TheList)
end
end.
solve() ->
timer:tc(?MODULE,dosolve,[1, -1, 1, []]).
Warning the code uses a huge amount of memory, collatz is not tail recursive, and it seems that there is some garbage collecting witch is not done.

Empty Map Pattern matches even for non-empty Map

The problem I am trying to solve states
Write a function map_search_pred(Map, Pred) that returns the first
element {Key,Value} in the map for which Pred(Key, Value) is true.
My attempt looks like
map_search_pred(#{}, _) -> {};
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
When I run this, I see output as
1> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{}
2> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{}
3> maps:size(#{}).
0
4>
How am I so sure?
I pulled out the first clause so it looks like
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
and run again
1> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{1,1}
2> lib_misc:map_search_pred(#{}, fun(X, Y) -> X =:= Y end).
** exception error: no match of right hand side value []
in function lib_misc:map_search_pred/2 (/Users/harith/code/IdeaProjects/others/erlang/programmingErlang/src/lib_misc.erl, line 42)
3>
According to map documentation:
Matching an expression against an empty map literal will match its type but no variables will be bound:
#{} = Expr
This expression will match if the expression Expr is of type map, otherwise it will fail with an exception badmatch.
However erlang:map_size can be used instead:
map_search_pred(Map, _) when map_size(Map) == 0 ->
{};
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.

Create a closure in Erlang: why are variables not bound?

I have a piece of code that goes like this:
Fi_F = fun (F, I, Xs) ->
fun ( X ) ->
F( x_to_list(X, Xs, I) )
end
end,
I just need to turn a function of list to a function of one number. For example with Xs = [1,2,3] and I = 2, I expect this to grant me with function:
fun ( X ) -> F([ 1, X, 3]) end.
But somehow F, I and X are shadowed, not closured, so it fails in x_to_list with an empty list.
I'm still new to Erlang and think I'm missing something more conceptual, than a mere syntax problem.
UPD: Found a bug. I wrote x_to_list/3 this way:
x_to_list( X, L, I ) ->
lists:sublist(L, I) ++ [ X ] ++ lists:nthtail(I+1, L).
So it counts list elements from 0, not 1. When I call it with I = 3, it fails. So this is not about closuring.
I still have shadowing warnings though, but it is completely another issue.
A somewhat quick and dirty implementation of x_to_list/3 (just to test) would be:
x_to_list(X, Xs, I) ->
{ Pre, Post } = lists:split(I-1, Xs),
Pre ++ [X] ++ tl(Post).
Then, your code works without problems:
> Q = fun ( F, I, Xs ) -> fun (X) -> F( x_to_list(X, Xs, I)) end end.
> Y = Q( fun(L) -> io:format("~p, ~p, ~p~n", L) end, 2, [1,2,3] ).
> Y(4).
1, 4, 3
ok

Resources