I have a module which written into notepad:
-module(hhfuns).
-compile(export_all).
one() -> 1.
two() -> 2.
add(X,Y) - X() + Y().
and I save it as hhfuns.erl. When I run Ok then I called:
hhfuns:add(myfun hhfun:one/0, myfun hhfun:two/0).
this command make syntax error. But when I changed myfun to fun it worked.maybe it's a basic syntax but I'm new at Erlang, so please explain for me why.
When you are passing function from outside module as a parameter you should use syntax fun Module:Function/Arity. Correct version for you will be hhfuns:add(fun hhfun:one/0, fun hhfun:two/0). fun here is a required keyword and you can not use myfun here instead.
In fact myfun is not an Erlang keyword, whereas fun is.
Related
I wrote a Hello-World module and compiled it successfully. And then I tried to learn the things under the hood by using erl_scan and erl_parse.
-module(useless).
-export([hello/0]).
hello() -> io:format("hello world\n").
and I type in the erl shell
{ok, S} = file:read_file("useless.erl").
and
{ok, T, _} = erl_scan:string(binary_to_list(S)).
It works fine apparently. But when I try erl_parse:parse_form(T).
It gives {error,{2,erl_parse,["syntax error before: ","'-'"]}}
What am I doing wrong?
Edit:
the module compile is helpful.
Also this is cool.
The function erl_parse:parse_form/1 works on one form only. So you must split the result of erl_scan:string/1 into individual forms first.
you can use erl_scan:tokens to achieve this (this code wors, but I am not sure I use the function in the right way):
-module(useless).
-export([eval/1]).
eval(File) ->
{ok, B} = file:read_file(File),
Forms = scan(erl_scan:tokens([],binary_to_list(B),1),[]),
F = fun(X) -> {ok,Y} = erl_parse:parse_form(X), Y end,
[F(X) || X <- Forms].
scan({done,{ok,T,N},S},Res) ->
scan(erl_scan:tokens([],S,N),[T|Res]);
scan(_,Res) ->
lists:reverse(Res).
Robert suggestion is to use the re-entrant feature of erl_scan:tokens/3.
The docs on this function are not explicit and it took me some time to understand that the initial string needed to be closed by eof. (if not the tokens function runs an endless loop).
Here is the code I finally came up with, I hope that will help others.
eval(File)->
{ok, Data} = file:read_file(File),
String=erlang:binary_to_list(Data),
scan(String).
scan(String) when is_list(String)->
scan(String++eof,[]). %% appended eof
scan({done, Result, LeftOverChars},Acc)->
scan_done(Result,LeftOverChars,Acc);
scan({more, Continuation},Acc)->
scan(erl_scan:tokens(Continuation,[],1),Acc);
scan(String,Acc) when is_list(String)->
scan(erl_scan:tokens([],String,1),Acc).
scan_done({error,ErrorMsg,_Location},_LeftOverChars,_Acc)->
ErrorMsg;
scan_done({eof,Location},LeftOverChars,Acc)->
Acc;
scan_done({ok,Tokens,Location},LeftOverChars,Acc)->
case erl_parse:parse_form(Tokens) of
{ok,R}->scan(LeftOverChars,Acc++[R]);
{error,R}->scan(LeftOverChars,R)
end.
I found this function Exec here http://fsharp.github.io/FAKE/apidocs/fake-processhelper-shell.html.
Target "UpdateTools" (fun _ ->
Exec "cmd"
)
But I keep getting this error, when I try to run it: "The value or constructor 'Exec' is not defined".
I'm new to FAKE and have not used F#, so forgive me if this should be obvious.
Can someone tell me why this api is not accessible like that?
The documentation is documenting class Shell. That means, you need to call it like:
Target "UpdateTools" (fun _ ->
ignore(Shell.Exec "cmd")
)
or, if you need to work with the error code further:
Target "UpdateTools" (fun _ ->
let errorCode = Shell.Exec "cmd"
//do something with the error code
()
)
Hope it is a bit clearer now.
I have been learning erlang for the past week and am going through Joe Armstrong's Pragmatic erlang book . I was writing some code to spawn processes and have come across a situation
I have a function in module myatom.erl which looks like this
start(anatom,Fun) ->
case whereis(anatom) of
undefined ->
Pid = spawn(Fun),
try register(anatom,Pid) of
true -> true
catch
error:Reason ->
Reason
end;
Other -> {error,already_defined}
end.
There is a function in another module named tloop.erl
loop() ->
receive
{ From , No } -> From ! { self(), No*4};
Other -> void
end.
if I am to use start() to spawn loop in the erlang shell , how can I do it ?
I get the following error when I do
anatom:start(atomname,tloop:loop).
Thanks in advance !
anatom:start(myatom,fun tloop:loop).
* 2: syntax error before: ')
You must write the following
anatom:start(myatom, fun tloop:loop/0).
You have to specify the arity (number of arguments) of the function, as in erlang functions with the same name but different arity are not considered to be the same function.
Is there a straightforward way to convert an Erlang fun to a string? A call to io_lib:format only prints the function reference, e.g. something like "#Fun<erl_eval.20.67289768>". For example, I'd like to be able to do this:
1> Fun = fun() -> atom_to_list('hello world') end.
2> FunStr = fun_to_str(Fun).
"fun() -> atom_to_list('hello world') end."
I'm looking for how to implement fun_to_str. In javascript, some interpreters have a .toSource() function that can be called on any object, including functions, that print their string representation. Any info is appreciated, thanks.
First, get the environment variables for the fun (which includes the abstract code):
1> {env, [{_, _, _, Abs}]} = erlang:fun_info(Fun, env).
{env,[{[],
{eval,#Fun<shell.21.83096281>},
{value,#Fun<shell.5.83096281>},
[{clause,1,[],[],
[{call,1,{atom,1,atom_to_list},[{atom,1,hello_world}]}]}]}]}
Pretty print the abstract code using erl_pp:
3> Str = erl_pp:expr({'fun', 1, {clauses, Abs}}).
[[[["fun",
[[[[["()"]," ->"],
["\n ",
[["atom_to_list",[[40,["'hello world'",41]]]]]]]]]]],
[10,["end"]]]]
4> io:format([Str|"\n"]).
fun() ->
atom_to_list('hello world')
end
ok
(You have to add {'fun', 1, {clauses, ...}} around it to make it a complete Erlang expression)
You might be able to use erlang:fun_info/2 for that, atleast i get some information from the shell when doing
1> erlang:fun_info(fun() -> test,ok end, env).
{env,[[],
{value,#Fun<shell.7.37281544>},
{eval,#Fun<shell.24.85590193>},
[{clause,1,[],[],[{atom,1,test},{atom,1,ok}]}]]}
2>
You want the last list with the clause atom and then pretty print it using for instance erl_pp
I need to debug some module in foreign system. The module has public function foo() - how can I know place (module and function name)
from which foo() given module was called? I mean stack of calls.
I cannot stop system, all work I can do by reload this module (but with some debug info).
-module(given).
-export(foo/0).
foo() ->
%% here is my debug - and
%% i need here(!) known about unknown_module:unknown_foo!
ok.
---
-module(unknown_module).
..
unknown_foo() ->
given:foo(). %% see above
Here's a simple trick:
Trace = try throw(42) catch 42 -> erlang:get_stacktrace() end,
erlang:display(Trace)
This might work:
where_am_i() ->
try throw(a)
catch throw:a:Stacktrace ->
Stacktrace
end.
Except that it doesn't work for tail calls. For example, given these two functions:
foo() ->
where_am_i().
bar() ->
X = where_am_i(),
{ok, X}.
I get these results:
4> foo:foo().
[{foo,where_am_i,0},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]
5> foo:bar().
{ok,[{foo,where_am_i,0},
{foo,bar,0},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
That is, I can only see bar, since foo's call frame has been left already when where_am_i is called.
io:format("~s~n", [element(2, process_info(self(), backtrace))]).
self() can be replaced by any other pid (rpc:pinfo should even work with remote procs). This helps if you cannot even modify the source or beam.
Here is my code for doing this:
format_stack_entry(S) ->
{Module,Fun,Arity,[{file,File},{line,Line}]}=S,
io_lib:format("{~p,~p,~p,[{file,~p},{line,~p]}",[Module,Fun,Arity,File,Line]).
stacktop([Top|_]) ->
Top.
ancestor(N) ->
{_,Stacktrace}=erlang:process_info(self(),current_stacktrace),
ancestor(N+1,Stacktrace).
ancestor(1,S) ->
format_stack_entry(stacktop(S));
ancestor(N,[_|T]) ->
ancestor(N-1,T).
info(Format) -> io:format(lists:concat([ancestor(2),Format,"\r"])).
info(Format,Args) -> io:format(lists:concat([ancestor(2),Format,"\r"]),Args).
Lists is a custom module in the system. Use your foo module instead.