Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language Erlang

(Concurrent solution)

Date:05/15/07
Author:Bill Clementson
URL:http://bc.tech.coop/blog
Comments:6
Info:http://www.erlang.org/
Score: (2.86 in 42 votes)
-module(beersong).
-export([sing/0]).
-define(TEMPLATE_0, "~s of beer on the wall, ~s of beer.~nGo to the store and buy some more, 99
bottles of beer on the wall.~n").
-define(TEMPLATE_N, "~s of beer on the wall, ~s of beer.~nTake one down and pass it around, ~s of
beer on the wall.~n~n").

create_verse(0)      -> {0, io_lib:format(?TEMPLATE_0, phrase(0))};
create_verse(Bottle) -> {Bottle, io_lib:format(?TEMPLATE_N, phrase(Bottle))}.

phrase(0)      -> ["No more bottles", "no more bottles"];
phrase(1)      -> ["1 bottle", "1 bottle", "no more bottles"];
phrase(2)      -> ["2 bottles", "2 bottles", "1 bottle"];
phrase(Bottle) -> lists:duplicate(2, integer_to_list(Bottle) ++ " bottles") ++
[integer_to_list(Bottle-1) ++ " bottles"].

bottles() -> lists:reverse(lists:seq(0,99)).

sing() ->
    lists:foreach(fun spawn_singer/1, bottles()),
    sing_verse(99).

spawn_singer(Bottle) ->
    Pid = self(), 
    spawn(fun() -> Pid ! create_verse(Bottle) end).

sing_verse(Bottle) ->
    receive
	{_, Verse} when Bottle == 0 ->
	    io:format(Verse);
	{N, Verse} when Bottle == N ->
	    io:format(Verse),
	    sing_verse(Bottle-1)
    after 
	3000 ->
	    io:format("Verse not received - re-starting singer~n"),
	    spawn_singer(Bottle),
	    sing_verse(Bottle)
    end.

Download Source | Write Comment

Alternative Versions

VersionAuthorDateCommentsRate
proper version - simple codeHåkan Stenholm01/23/061
advanced with exact last verseKurt J. Bosch06/27/051

Comments

>>  Bill Clementson said on 05/28/07 02:24:31

Bill Clementson My weblog entry for this post is here: http://bc.tech.coop/blog/070514.html

>>   said on 05/16/08 10:44:00

Ha, try doing that in just 39 lines with Java.

>>  Jimmy Ruska said on 03/07/10 10:12:28

Jimmy Ruska % using Joe's pmap function from the programming erlang book
-module(test).
-export([goTime/0]).

pmap(F, L) ->
S = self(),
Ref = erlang:make_ref(),
Pids = lists:map(fun(I) -> spawn(fun() -> do_f(S, Ref, F, I) end) end, L),
gather(Pids, Ref).
do_f(Parent, Ref, F, I) ->
Parent ! {self(), Ref, (catch F(I))}.
gather([Pid|T], Ref) ->
receive
{Pid, Ref, Ret} -> [Ret|gather(T, Ref)]
end;
gather([], _) ->
[].

beerSong(N) ->
case N of
0 -> "Out of Beer\n";
1 -> "1 bottle of beer on the wall one bottle beer, take one down, pass it around, no beer\n";
2 -> "2 bottles of beer on the wall one bottle beer, take one down, pass it around, 1 beer on the wall\n";
N -> X=integer_to_list(N), [Z]=X, [X," bottles of beer on the wall ",X," bottles of beer, take one down pass it around ",[Z-1]," bottles of beer on the wall\n"]
end.
bs(N) -> io:format(beerSong(N)).

goTime() -> spawn(fun() -> pmap(fun bs/1, lists:reverse(lists:seq(0,99))) end), theGame.

>>  Jimmy said on 03/07/10 10:26:40

Jimmy whoops, should be Z=integer_to_list(N-1), then just Z instead of [Z-1].

>>  Jimmy Ruska said on 03/20/10 04:02:27

Jimmy Ruska Smaller still

pmap(F, L,Parent) -> [receive {Pid, Res} -> Res end || Pid <- [spawn(fun() -> Parent ! {self(), F(X)} end) || X <- L]].
goTime() -> pmap(fun(Line) -> io:format(beerSong(Line)) end, lists:reverse(lists:seq(0,99)),self()), 'The Game'.
beerSong(N) when N=:=0 -> "Out of Beer\n";
beerSong(N) when N=:=1 -> "1 bottle of beer on the wall 1 bottle beer, take one down, pass it around, no beer\n";
beerSong(N) when N=:=2 -> "2 bottles of beer on the wall 2 bottle beer, take one down, pass it around, 1 beer on the wall\n";
beerSong(N) -> [integer_to_list(N)," bottles of beer on the wall ",integer_to_list(N)," bottles of beer, take one down pass it around ",integer_to_list(N-1)," bottles of beer on the wall\n"].

>>  Christopher Atkins said on 04/17/10 18:42:51

Christopher Atkins If they had a challenge to sing it in the round, parallelism would be useful. In the meantime, here's the simplest program I can imagine. It leverages recursive pattern matching and should be tail recursive.

-module(beer).
-export([song/0]).

song(0) ->
io:format("No more bottles of beer on the wall, no more bottles of beer.~nGo to the store and buy some more, 99 bottles of beer on the wall.~n~n";);
song(1) ->
io:format("1 more bottle of beer on the wall, 1 more bottle of beer.~nTake one down and pass it around, no more bottles of beer on the wall.~n~n";),
song(0);
song(2) ->
io:format("2 more bottles of beer on the wall, 2 more bottles of beer.~nTake one down and pass it around, 1 more bottle of beer on the wall.~n~n";),
song(1);
song(N) ->
io:format("~p bottles of beer on the wall, ~p bottles of beer.~nTake one down and pass it around. ~p bottles of beer on the wall.~n~n", [N,N,N-1]),
song(N-1).
song() ->
song(99).

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: