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
Version | Author | Date | Comments | Rate |
---|---|---|---|---|
proper version - simple code | Håkan Stenholm | 01/23/06 | 1 | |
advanced with exact last verse | Kurt J. Bosch | 06/27/05 | 1 |
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!
Comments
Bill Clementson said on 05/28/07 02:24:31
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
% 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
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
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
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).