2> Adder = fun(X,Y) -> X+Y end. #Fun<erl_eval.12.113037538> 3> AddTwo = fun(X) -> Adder(2,X) end. #Fun<erl_eval.6.13229925> 4> Adder(3,4). 7 5> AddTwo(5). 7
Thursday, 1 October 2009
Wednesday, 30 September 2009
functions and funs
To create a function that takes a fun as an argument
1: mangle(F, X) ->
2: F(X).
4> play:mangle(fun(X) -> (X*X) end, 3).
Remember that if you’re defining the fun inline to add the end still – or you’ll see
* 1: syntax error before: ')'
To pass in a function to something that needs a fun, pass a function reference and remember the arity
1: double(X) ->
2: 2*X.
6> play:mangle(fun play:double/1, 3). 6
And finally to create a function that returns a fun
1: getMangler() ->
2: (fun(X) ->
3: play:double(X) end).
4:
1> Mangler = play:getMangler(). #Fun<play.0.65855982> 2> Mangler(3). 6 3> play:mangle(Mangler, 3). 6
and you can naturally just put the getMangler into the call direct:
4> play:mangle(play:getMangler(), 3). 6
Note that this won’t work:
5> play:mangle(fun play:getMangler/0, 3).
** exception error: play:getMangler/0 called with one argument
in function play:mangle/2
because you’re attempting to call getMangler with the argument 3.
Monday, 28 September 2009
tuples and templates
How can we be sure that we produce and consume tuples that are of the form we expect? Do we have to wait to runtime?
process management
Processes hang around, as you might expect. First of all, pman is the Erlang process manager. Start with
1> pman:start().
Hide system processes to make it a bit clearer for now. If we run the simple message passing example from here, then we can see that a play:receiver() process is left hanging around after everything stops.
2> play:start(). in receiver <0.46.0> rx: hey <0.47.0> <0.47.0> in receiver <0.46.0>
To kill the process, highlight it with a click and choose Trace/Kill. pman has a default 5s refresh, so it’ll not disappear immediately…
message passing
1: -module(play).
2: -export([headstrip/1,message/1,start/0,receiver/0,sender/1]).
3:
4: sender(RxPid) ->
5: RxPid ! {hey, self()}.
6:
7: receiver() ->
8: io:format("in receiver ~p~n",[self()]),
9: receive
10: {hey, TxPid} -> io:format("rx: ~p ~p~n",[hey, TxPid])
11: end.
12:
13: start() ->
14: RxPid = spawn(play, receiver, []),
15: spawn(play, sender, [RxPid]).
28> play:start(). in receiver rx: hey <0.150.0>
receive blocks, and handles one message
If you want your receiver to hang around, call it again. e.g. add a call to receiver() just before end in the code above. But then – whole process finishes. Is something running in the background still? How do I check? [see http://timbar.blogspot.com/2009/09/process-management.html]
remember to export
Remember that every function called must be exported – not just the bootstrap function you use to kick things off. In this context the error
=ERROR REPORT==== 25-Sep-2009::16:51:33 ===
Error in process <0.98.0> with exit value: {undef,[{play,sender,[<0.97.0>]}]}
indicates that you've forgotten to export the function "sender".
unhandlable messages are just dropped
Messages that receive doesn’t know how to handle are just forgotten. How to do a default response? Try sending eef instead of hey in the code above.
Friday, 25 September 2009
difference between foreach and map
map creates a new list from an existing list by applying a function to each existing member.
Use foreach if you want to trigger actions based on list members, not just create new list members.
For example – working from a list of contacts you might want to send a message to everyone whose name matches some string. You’ve no reason to create a new list in this case.
To message an agent – or not – assume we have this function:
1: -module(play).
2: -export([message/1]).
3:
4: message({Agent,Location}) when Agent == "John" ->
5: io:format("Messaging ~w in ~w~n",[Agent,Location]);
6: message({Agent,Location}) ->
7: io:format("No message for ~w~n",[Agent]).
5> play:message({"John","Buenos Aires"}).
Messaging [74,111,104,110] in [66,117,101,110,111,115,32,65,105,114,101,115]
ok
6> play:message({"Jeff","Buenos Aires"}).
No message for [74,101,102,102]
ok
(Ha, unexpectedly turns strings to lists of ASCII character codes. Need to look into string handling.)
3> lists:foreach(fun play:message/1, [{"John","Buenos Aires"}, {"Jules","Nairobi"}]).
Messaging [74,111,104,110] in [66,117,101,110,111,115,32,65,105,114,101,115]
No message for [74,117,108,101,115]
ok
Surprised by the need to recast our message function explicitly as a fun to pass it to foreach. Need to look into that too. Is it because passing a naked play:message/1 looks like an atom?
function signature dropthrough a bit like case
1: price_by_age({car,Age}) -> 10 * (10 - Age);
2: price_by_age({boat,Age}) -> 20 * (20 - Age).
is equivalent to
1: price_by_age(Vehicle) ->2: case Vehicle of
3: {car,Age} -> 10 * (10 - Age); 4: {boat,Age} -> 20 * (20 - Age) 5: end.recursive and iterative
1: sum([H|T]) -> H + sum(T);
2: sum([]) -> 0.
1 + sum(2,3) 1 + 2 + sum(3) 1 + 2 + 3 + sum() 6
1: sum(L) -> sum(L,0).
2:
3: sum([H|T],Accumulator) -> sum(T,Accumulator + H);
4: sum([],Accumulator) -> Accumulator.
sum([2,3], 1) sum([3], 3) sum([], 6) 6
Using the accumulator means you can pass state to the next call rather than having to keep all your state hanging around while you progress.
Thursday, 24 September 2009
head strip with guard
1: -module(play).
2: -export([headstrip/1]).
3:
4: headstrip([]) -> ok;
5: headstrip([Head|Rest]) when Head > 4 ->
6: io:format("~w bingo!~n", [Head]),
7: headstrip(Rest);
8: headstrip([Head|Rest]) ->
9: io:format("~w~n",[Head]),
10: headstrip(Rest).
3> play:headstrip([1,2,3,4,5,6,7,8,9]). 1 2 2 3 4 5 bingo! 6 bingo! 7 bingo! 8 bingo! 9 bingo! ok