Funimpaired
January 7, 2009
Our discussion of anonymous functions has inspired David Budworth to devote a whole new blog to functional programming.
Check it out:
http://funimpaired.wordpress.com/2009/01/06/hello-world/
I’m really looking forward to learning what you have to share, David. Love the title.
All the best,
LRP
More Fun
January 5, 2009
Boy I’d like to buy David Budworth a beer.
His comment on anonymous functions is so good I’m going to repost it here. Now maybe I have enough background to dig back into Joe’s Simple Server to see how he’s using these funny beasts.
Thanks, David.
P.S. Can anyone suggest additional use cases?
Hi There,
Primary uses (for me) of anon funs is for the collection abstractions (map, fold, etc).
And the big one is for process work.
Lets say I want to spin off a complex computation, I can do
do_complex_stuff(Arg1,Arg2,Arg3) -> ….
elswhere() -> spawn(?MODULE,do_complex_stuff,[1,2,3]).
- or -
elsewhere() -> spawn( fun() -> do_complex_stuff(1,2,3) end).
No big diff, right? well, what if “do_complex_stuff” is not a method I want to expose to the general public? the M:F/A style requires the function to be exported. If I create a fun(), I can call anything in my own module or anything exported from others.
Now, suppose I wanted a slightly more funky thing:
do_with_next_seq(M,F) -> M:F(my_next_seq()).
(pretend that do_with_next_seq does something like pull a seqno from a table or something tricky with it’s own process state).
Now, if I wanted to pass in a function that does something terribly cool, like send me back a status message, how would I build that?
Change that function to be
do_with_next_seq(M,F,Args) -> M:F([my_next_seq()|Args])
but now I have to modify that guy, and what if there are no extra args. It makes “do_with_next_seq” too specific.
if it was:
do_with_next_seq(Fun) -> Fun(my_next_seq()).
then the consumer could do:
stuff() ->
Me = self(),
other_mod:do_with_next_seq(fun(S) -> Me ! {seq_was,S}, do_my_stuff(S) end)
now, with or without extra params, doesn’t matter. I don’t need to change the called function.
As an anon-function generated inline within another function, I have access to the variables of that enclosing function. something difficult or annoying at least to do with the M:F/A style of fun passing.
Hope that wasn’t even more confusing.
Happy New Year! Are We Having Fun?
January 4, 2009
The old garret’s all spic-and-span. Well, bit of spic, not much span. But now I can more or less maneuver among the piles. Just don’t ask me to find anything.
Development network is back up. Still a few pesky issues to iron out, but all in good time.
During the last movie your all-to-cocky hero was gravely wounded and bleeding in the dust due to his own ignorance. Dude was brought low by Erlang funs.
Now, due to the thankful healing influences of holiday libations, your tragicomic hero is ready to climb back on his trusty steed in the name of truth, justice, and the American Way.
But first:
Funs
If I understand Joe Armstrong, pattern matching, functions, and concurrency are the three beating hearts of Erlang. He tells us that higher-order functions will “breathe fire into the belly of (our) code.”
I want to believe.
But so far I just don’t get it. I can appreciate the beauty of map, filter, and list comprehensions. But what I don’t understand is why we need anonymous functions to do the dirty work. I’m sure there are good, perhaps essential, reasons but, as you know, I’m slow.
In every example between pages 42 and 48 of Programming Erlang we note two things:
- Every example of an anonymous function is defined in the Erlang shell.
- Every example of an anonymous function is assigned to a variable.
Best I can tell anonymous functions can’t be defined inside a module unless defined inside a named function. For instance, this fails:
-module(blip).
fun(P,I) -> P * I end,
Here’s what I get when I try to compile it:
1> c(blip).
./blip.erl:6: syntax error before: ‘fun’
error
Nor does this work:
-module(blip).
Test = fun(P,I) -> P * I end,
I get this:
1> c(blip).
./blip.erl:6: syntax error before: Test
error
In short, it seems that I can’t just blithely define an anonymous function, assign it to a variable, and pass that variable into a half dozen functions in my module.
test/2, below, works. But test1/2 is simpler.
-module(blip).
-export([test/2, test1/2]).
%% Principal: floating point
%% Interest: floating point
test(Principal, Interest) ->
Earned = fun(P,I) -> P * I end,
Balance = fun(P, I) -> Earned(P, I) + P end,
E = Earned(Principal, Interest),
B = Balance(Principal, Interest),
io:format(“Earned: ~.2f Balance: ~.2f~n”, [E, B]).
test1(Principal, Interest) ->
Earned = Principal * Interest,
Balance = (Principal * Interest) + Principal,
io:format(“Earned: ~.2f Balance: ~.2f~n”, [Earned, Balance]).
Here’s a slightly more useful function along the same lines:
-module(money).
-export([return/4]).
%% Growth of principal over term at given interest rate compounded annually
%% Term – Integer: e.g. 5
%% Interest – Floating Point: e.g. 0.04
%% Principal- Floating Point: e.g. 50000.00
%% Age – Age of account: initialize with 0
return(Term, Interest, Principal, Age) ->
Earned = Interest * Principal,
Balance = Earned + Principal,
Term_Remaining = Term – 1,
Year = Age + 1,
io:format(“Year: ~p Earned: ~.2f Balance: ~.2f~n”, [Year, Earned, Balance]),
return(Term_Remaining, Interest, Balance, Year).
I’m sure this is far from the most elegant Erlang code in the world, but I don’t see how anonymous functions would contribute much beyond greater complexity.
Moreover, if we’re going to assign our anonymous functions to variables, they are no longer anonymous. Why not just name them to begin with?
So, here’re my Micky The Dunce questions for the day:
- Under what circumstances should we consider using anonymous functions?
- Are there any circumstances under which anonymous functions are absolutely essential?
- How can I make my code breathe fire?