Erlang error: no function clause matching io:request - erlang

I'm an experienced programmer new to Erlang and I'm stuck on the following:
myread() ->
{_, MyData } = file:read_file( "hands.txt" ),
io:format( "hands-out.txt", "~w", MyData ).
yields, when myread() is invoked from the shell:
** exception error: no function clause matching io:request("hands-out.txt",
{format,"~w", <<"3h 5h 7h 8h 3h 5h 7h 8h q"...>>})
(io.erl, line 556) in function io:o_request/3 (io.erl, line 63)
Any help would be appreciated.

Two things:
"hands-out.txt", "~w" needs to be one string: "hands-out.txt: ~w"
and the data that's replacing the ~w needs to be a list. So:
io:format( "hands-out.txt: ~w", [MyData] ).
See http://erlang.org/doc/man/io.html#format-2
Also, you should pattern match on the status value in the return from file:read_file/1. In your version, an error, which would be returned as {error, Reason} would match here, since you're using _, and you'd print the error reason rather than the file, which might be confusing.
So either make it {ok, MyData } = file:read_file( "hands.txt" ) if you want to crash on read error, or something like the following if you want to handle that case:
myread() ->
case file:read_file( "hands.txt" ) of
{ok, MyData } ->
io:format( "hands-out.txt: ~w", [MyData] );
{error, Error} ->
io:format("Error: ~w~n", [Error])
end.

Related

How to case switch in erlang using a function value?

This program is crashing despite seeming to work. I don't understand why though. I'm trying to accomplish a deep merge and need conditional logic.
Given the following list:
ManOne = #{ "Bob" => #{"Sagget" => #{}} }
ManTwo = #{ "Bob" => #{"Daniels" => #{}} }
I'm trying to compare them as follows, this function returns true as expected:
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
merger(M1, M2) ->
M1_Keys = maps:keys(M1),
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
io:fwrite("Check is: ~p\n", [Check]),
case Check of
{ok, true} ->
io:fwrite("true\n");
{ok, false} ->
io:fwrite("false\n")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) ->
ok.
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
gives the following output:
Check is: {ok,true}
true
{"init terminating in do_boot",{{badmap,ok},[{maps,keys,[ok],[]},{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()
Crash dump is being written to: erl_crash.dump...done
Let's go over your question first because there's a few misconceptions and/or corrections that we can make.
Your Description
This program is crashing despite seeming to work. I don't understand why though. I'm trying to accomplish a deep merge and need conditional logic.
Given the following list:
ManOne = #{ "Bob" => #{"Sagget" => #{}} }
ManTwo = #{ "Bob" => #{"Daniels" => #{}} }
Note that the above are NOT lists, they are maps, which function entirely differently.
A map is, for all intents and purposes, a lookup table until it contains ~31 key/value pairs.
At this point, it becomes a HashMap (this can be seen by viewing the elements as they become unordered after the map becomes a HashMap).
I'm trying to compare them as follows, this function returns true as expected:
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
This is an incorrect way to assert equality; in erlang, it is suggested to not use == to check equality.
Instead, =:= should be used.
The reason for this is due to the fact that == does NOT check the type of the elements it is comparing and only takes a fuzzy value - i.e 1 == 1.0 will return true but 1 =:= 1.0 will return false.
Personally, I would recommend instead using Erlang's Pattern-Matching to check your values.
This could be implemented using the following snippet:
-spec check_if_same(M1 :: map(), M2 :: map()) -> boolean().
check_if_same(M1, M2) ->
SortedKeys1 = lists:sort(maps:keys(M1)),
SortedKeys2 = lists:sort(maps:keys(M2)),
%% We hide the implementation of the function in
%% a function with the same name suffixed with an
%% underscore. This allows us to have a public api
%% but keep the implementation internal which allows
%% the code to be a bit cleaner.
check_if_same_(SortedKeys1, SortedKeys2).
%% If they're both empty then we've gone through
%% every key meaning that they must be identical
check_if_same_([], []) ->
true;
%% If the current Key on both heads is the same
%% then recurse and check the next and so on
check_if_same_([Key|Tail1], [Key|Tail2]) ->
check_if_same_(Tail1, Tail2);
%% If we get anything else, e.g more keys in
%% one than the other or the keys don't match,
%% then we'll fall in to this case.
%% As we know anything that falls in to this
%% case doesn't match, we just return false
check_if_same_(Keys1, Keys2) when is_list(Keys1), is_list(Keys2) ->
false.
Note that in the above snippet, I only ever returned true or false - my recommendation for cleaner code would be to keep to the following formats;
ok - This is typically for functions where you care about the effect and not the return
true | false - This is typically for comparison functions, i.e is_binary/1, is_function/1
{ok, Value} - This would typically be for any function where you care about the value returned
{error, Reason} - This would be used whenever you expect an error so that you can bubble the error back up the chain with an easy-to-match format
Your Code Snippet
merger(M1, M2) ->
M1_Keys = maps:keys(M1),
%% Note that you don't use the M2Keys here so you don't need to do the work to get them
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
%% It's generally recommended to stick to io:format/2 rather than io:fwrite/2
io:fwrite("Check is: ~p\n", [Check]),
case Check of
{ok, true} ->
io:fwrite("true\n");
{ok, false} ->
io:fwrite("false\n")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) ->
ok.
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
Now, the above snippet (other than being a bit inefficient) is perfectly okay erlang and will work as expected
gives the following output:
Check is: {ok,true}
true
{"init terminating in do_boot",{{badmap,ok},[{maps,keys,[ok],[]},{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()
Crash dump is being written to: erl_crash.dump...done
This crash dump is where the real issue is;
Check is: {ok,true}
true
From this we can tell that we
Hit the io:fwrite/2 (io:fwrite("Check is: ~p\n", [Check]))
Entered the {ok, true} path in the case (io:fwrite("true\n"))
The next line is where we see the actual problem, let's break it down:
"init terminating in do_boot" - We failed when starting up, this might be when running an escript or starting an app
Now let's break down that tuple:
{
{badmap,ok}, %% The function we called expected a map and we passed in 'ok'
[
{maps,keys,[ok],[]}, %% We called maps:keys/1 with 'ok' as an arg
{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]}, %% This was called at helloworld:merger/2 (helloworld.erl:9)
{init,start_em,1,[]},{init,do_boot,3,[]} %% We failed on start up
]
}
What we can take away from this is that you're calling merger in your code with an invalid value of ok on line 9 of helloworld.erl
There is some missing information. Although this code looks like a first draft or step, it works as expected. I tested it in the shell and got this:
-module (merger).
-compile(export_all).
merger(M1, M2) ->
M1_Keys = maps:keys(M1),
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
io:fwrite("Check is: ~p\n", [Check]),
case Check of
{ok, true} ->
io:fwrite("true\n");
{ok, false} ->
io:fwrite("false\n")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) ->
ok.
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
test() ->
merger(#{ "Bob" => #{"Sagget" => #{}} },#{ "Bob" => #{"Daniels" => #{}} }).
which gives:
8> c(merger).
merger.erl:3: Warning: export_all flag enabled - all functions will be exported
merger.erl:7: Warning: variable 'M2_Keys' is unused
merger.erl:9: Warning: variable 'Head' is unused
merger.erl:19: Warning: variable 'M1' is unused
merger.erl:19: Warning: variable 'M2' is unused
{ok,merger}
9> merger:test().
Check is: {ok,true}
true
ok
10>
Maybe you could also tell us what is the expected result of merging ManOne and ManTwo

Is there a way to tell whether a function has a matching clause without calling it in Erlang?

E.g. suppose I have a module named caller, and one of the functions defined therein contains this expression:
Callee:some_function(foo, Bar)
caller could try to catch function_clause, but how would caller know that it comes directly from Callee:some_function as opposed to some other function call (e.g. a call that Callee:some_function itself makes)?
You could catch function_clause errors with try-catch, and check if the stacktrace matches:
-module(foo).
-compile(export_all).
maybe_apply(Mod, Fun, Args) ->
try apply(Mod, Fun, Args)
catch
error:function_clause ->
case erlang:get_stacktrace() of
[{Mod, Fun, Args} | _] ->
{error, function_clause};
[{Mod, Fun, Args, _LineNumber} | _] ->
{error, function_clause};
Stacktrace ->
{error, other_function_clause, Stacktrace}
end
end.
Here is an example that shows how it distinguishes between a function clause error in lists:filter itself, and a function clause in a function called by lists:filter:
> foo:maybe_apply(lists, filter, [x, [1,2,3]]).
{error,function_clause}
> foo:maybe_apply(lists, filter, [fun(x) -> true end, [1,2,3]]).
{error,other_function_clause,
[{erl_eval,'-inside-an-interpreted-fun-',[1],[]},
{erl_eval,expr,3,[]}]}
You can use catch (callee:some_function(foo, Bar)) and analyse the error message if any:
1> catch (lists:filter(5,[1,2,3])).
{'EXIT',{function_clause,[{lists,filter,
[5,[1,2,3]],
[{file,"lists.erl"},{line,1283}]},
{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,
[{file,"shell.erl"},{line,624}]}]}}
2> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4}])).
[3,7]
3> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4,5}])).
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
[{3,4,5}],
[]},
{erl_eval,expr,3,[]}]}}
4>
4> catch(lists:map(fun ({X,Y}) -> X / Y end, [{1,2},{3,0}])).
{'EXIT',{badarith,[{erlang,'/',[3,0],[]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,624}]}]}}
5>
you can recognize the case that you are looking for because it has the form:
{'EXIT',{function_clause,[{callee,some_function,
[foo, Bar],
[{file,"callee.erl"},{line,LineNumber}]}|Stack]}}

Cowboy web server application very slow

I am currently playing around with minimal web servers, like Cowboy. I want to pass a number in the URL, load lines of a file, sort these lines and print the element in the middle to test IO and sorting.
So the code loads the path like /123, makes a padded "00123" out of the number, loads the file "input00123.txt" and sorts its content and then returns something like "input00123.txt 0.50000".
At the sime time I have a test tool which makes 50 simultaneous requests, where only 2 get answered, the rest times out.
My handler looks like the following:
-module(toppage_handler).
-export([init/3]).
-export([handle/2]).
-export([terminate/3]).
init(_Transport, Req, []) ->
{ok, Req, undefined}.
readlines(FileName) ->
{ok, Device} = file:open(FileName, [read]),
get_all_lines(Device, []).
get_all_lines(Device, Accum) ->
case io:get_line(Device, "") of
eof -> file:close(Device), Accum;
Line -> get_all_lines(Device, Accum ++ [Line])
end.
handle(Req, State) ->
{PathBin, _} = cowboy_req:path(Req),
case PathBin of
<<"/">> -> Output = <<"Hello, world!">>;
_ -> PathNum = string:substr(binary_to_list(PathBin),2),
Num = string:right(PathNum, 5, $0),
Filename = string:concat("input",string:concat(Num, ".txt")),
Filepath = string:concat("../data/",Filename),
SortedLines = lists:sort(readlines(Filepath)),
MiddleIndex = erlang:trunc(length(SortedLines)/2),
MiddleElement = lists:nth(MiddleIndex, SortedLines),
Output = iolist_to_binary(io_lib:format("~s\t~s",[Filename,MiddleElement]))
end,
{ok, ReqRes} = cowboy_req:reply(200, [], Output, Req),
{ok, ReqRes, State}.
terminate(_Reason, _Req, _State) ->
ok.
I am running this on Windows to compare it with .NET. Is there anything to make this more performant, like running the sorting/IO in threads or how can I improve it? Running with cygwin didn't change the result a lot, I got about 5-6 requests answered.
Thanks in advance!
The most glaring issue: get_all_lines is O(N^2) because list concatenation (++) is O(N). Erlang list type is a singly linked list. The typical approach here is to use "cons" operator, appending to the head of the list, and reverse accumulator at the end:
get_all_lines(Device, Accum) ->
case io:get_line(Device, "") of
eof -> file:close(Device), lists:reverse(Accum);
Line -> get_all_lines(Device, [Line | Accum])
end.
Pass binary flag to file:open to use binaries instead of strings (which are just lists of characters in Erlang), they are much more memory and CPU-friendly.

Erlang: supervisor:start_child/2 error has me baffled

I'm making slight modifications to Logan/Merritt/Carlson's simple cache, Chapter 6, pp 149-169, Erlang and OTP in Action. So far, no code changes, just renaming the modules.
I start the application:
application:start(gridz).
ok
I insert an item:
gridz_maker:insert(blip, blop).
I get this error:
** exception error: no match of right hand side value
{error,
{function_clause,
[{gridz_edit,init,
[{blop,86400}],
[{file,"src/gridz_edit.erl"},{line,51}]},
{gen_server,init_it,6,
[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}
in function gridz_maker:insert/2 (src/gridz_maker.erl, line 15)
Here's the code:
insert(Key, Value) ->
case gridz_store:lookup(Key) of
{ok, Pid} -> gridz_edit:replace(Pid, Value);
{error, _} -> {ok, Pid} = gridz_edit:create(Value), %% line 15
gridz_store:insert(Key, Pid)
end.
I look at line 15:
{error, _} -> {ok, Pid} = gridz_edit:create(Value),
I expect the error because this is a new item. gridz:edit is a gen_server (sc_element in Logan et/al.) Here's the code for create/1:
create(Value) ->
create(Value, ?DEFAULT_LEASE_TIME).
create(Value, LeaseTime) ->
gridz_sup:start_child(Value, LeaseTime).
And here's the code for gridz_sup:start_child/2:
start_child(Value, LeaseTime) ->
supervisor:start_child(?SERVER, [Value, LeaseTime]).
init([]) ->
Grid = {gridz_edit, {gridz_edit, start_link, []},
temporary, brutal_kill, worker, [gridz_edit]},
Children = [Grid],
RestartStrategy = {simple_one_for_one, 0, 1},
{ok, {RestartStrategy, Children}}.
If I execute supervisor:start_child/2 directly, here's what I get:
{error,{function_clause,[{gridz_edit,init,
[{blop,50400}],
[{file,"src/gridz_edit.erl"},{line,51}]},
{gen_server,init_it,6,
[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}
Line 51 in gridz_edit is an init function:
init([Value, LeaseTime]) ->
Now = calendar:local_time(),
StartTime = calendar:datetime_to_gregorian_seconds(Now),
{ok,
#state{value = Value,
lease_time = LeaseTime,
start_time = StartTime},
time_left(StartTime, LeaseTime)}.
If I execute it directly, it works:
120> gridz_edit:init([blop, (60 * 60 * 24)]).
{ok,{state,blop,86400,63537666408},86400000}
So now I'm baffled. What am I missing? Why does supervisor:start_child/2 throw an error?
Thanks,
LRP
The error says you are passing in a tuple with 2 members, {blop,86400}, when you seem to be expecting a list of 2 members: [Value, LeaseTime]. In your direct execution, you are also using a list, so it works. You should figure out where the tuple is being created, and create a list instead.

Error reports in Erlang

I've taken the cowboy example code and brooken it.
The code for the default request handler looked like this:
-module(default_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({_Any, http}, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
{ok, Req2} = cowboy_http_req:reply(200, [], <<"Hello world!">>, Req),
{ok, Req2, State}.
terminate(_Req, _State) ->
ok.
its straight forward, but I wanted to make return files so I changed it to:
-module(default_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({_Any, http}, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
try
{Path, Req1} = cowboy_http_req:path(Req),
{ok, File} = file:read_file(Path),
cowboy_http_req:reply(200, [], File, Req1)
of
{ok, Req2} ->
{ok, Req2, State}
catch
_ ->
{ok, Req3} = cowboy_http_req:reply(200, [], <<"Hello world!">>, Req),
{ok, Req3, State}
end.
terminate(_Req, _State) ->
ok.
The try-catch thing should handle the fact that there might not be a file, but it does not. Why is that?
When I try to fetch a file that is not there I get a large error report in the console, can anyone tell me why?
=ERROR REPORT==== 15-Jun-2012::14:24:54 ===
** Handler default_handler terminating in handle/2
for the reason error:{badmatch,{error,badarg}}
** Options were []
** Handler state was undefined
** Request was [{socket,#Port<0.1515>},
{transport,cowboy_tcp_transport},
{connection,keepalive},
{pid,<0.1175.0>},
{method,'GET'},
{version,{1,1}},
{peer,undefined},
{host,[<<"localhost">>]},
{host_info,undefined},
{raw_host,<<"localhost">>},
{port,8080},
{path,[<<"favicon.ico">>]},
{path_info,undefined},
{raw_path,<<"/favicon.ico">>},
{qs_vals,undefined},
{raw_qs,<<>>},
{bindings,[]},
{headers,
[{'Accept-Charset',<<"ISO-8859-1,utf-8;q=0.7,*;q=0.3">>},
{'Accept-Language',<<"en-US,en;q=0.8">>},
{'Accept-Encoding',<<"gzip,deflate,sdch">>},
{'User-Agent',
<<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/10.10 Chromium/18.0.1025.151 Chrome/18.0.1025.151 Safari/535.19">>},
{'Accept',<<"*/*">>},
{'Connection',<<"keep-alive">>},
{'Host',<<"localhost">>}]},
{p_headers,[{'Connection',[<<"keep-alive">>]}]},
{cookies,undefined},
{meta,[]},
{body_state,waiting},
{buffer,<<>>},
{resp_state,waiting},
{resp_headers,[]},
{resp_body,<<>>},
{onresponse,undefined},
{urldecode,{#Fun<cowboy_http.urldecode.2>,crash}}]
** Stacktrace: [{default_handler,handle,2,
[{file,"src/default_handler.erl"},{line,13}]},
{cowboy_http_protocol,handler_handle,3,
[{file,"src/cowboy_http_protocol.erl"},
{line,298}]}]
probably because of how it evaluates the catch clause, see http://www.erlang.org/doc/reference_manual/expressions.html#try
If an exception occurs during evaluation of Exprs but there is no matching ExceptionPattern of the right Class with a true guard sequence, the exception is passed on as if Exprs had not been enclosed in a try expression.
You need to specify an error class (error, throw or exit) if not looking for the default, which is throw.
try Exprs of
Pattern1 [when GuardSeq1] ->
Body1;
...;
PatternN [when GuardSeqN] ->
BodyN
catch
[Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] ->
ExceptionBody1;
...;
[ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] ->
ExceptionBodyN
a catch-all-errors would be written as
catch
_:_ ->
notice how you specify both class and ExpressionPattern as "don't care".
Hope this helps because I only 'dabbled' in erlang until now. :)
This line:
{Path, Req1} = cowboy_http_req:path(Req),
Actually returns a list of binaries, like [<<"path">>,<<"path2">>] instead of something like "/path/path2" which should be what you're actually looking for.
So, to form the filesystem path:
{Path, Req1} = cowboy_http_req:path(Req),
FsPath = lists:foldl(
fun(PathComponent, Acc) ->
string:join([Acc, erlang:binary_to_list(PathComponent)], "/")
end,
"",
Path
),
{ok, File} = file:read_file(FsPath),
(The badarg error you're getting is because the argument to file:read_file/1 is not a string (a list) but a list of binaries, which is not the expected argument.
And the catch needs a _:_ clause, just like Harald answer states.
Cheers.

Resources