<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Benjamin Halsted</title>
	<atom:link href="http://benjaminhalsted.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://benjaminhalsted.com</link>
	<description>// [bgh] todo, add something clever here.</description>
	<lastBuildDate>Mon, 28 Jun 2010 15:19:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Erlang Programming Exercise: 5-2</title>
		<link>http://benjaminhalsted.com/2010/06/erlang-programming-exercise-5-2/</link>
		<comments>http://benjaminhalsted.com/2010/06/erlang-programming-exercise-5-2/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 15:19:28 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=243</guid>
		<description><![CDATA[Exercise 5-2 involves changing the frequency server from earlier in the chapter. Here is the task list:

Restrict the deallocation of a frequency so that only the client that allocated it can deallocate it.
Fix a bug: Deallocating a frequency that isn't allocated crashes the server
Only allow shutdown of the frequency server if there are no allocated [...]]]></description>
			<content:encoded><![CDATA[<p>Exercise 5-2 involves changing the frequency server from earlier in the chapter. Here is the task list:</p>
<ul>
<li>Restrict the deallocation of a frequency so that only the client that allocated it can deallocate it.</li>
<li>Fix a bug: Deallocating a frequency that isn't allocated crashes the server</li>
<li>Only allow shutdown of the frequency server if there are no allocated frequencies</li>
<li>Limit the number of frequencies a client can allocate to 3</li>
</ul>
<p>I worked through the tasks and then had a bit of fun with the server. I changed the shutdown sequence so that deallocations work while shutting down but allocations return an error. Once all of the outstanding frequencies have been returned it will complete the shutdown.</p>
<p>As you can see in the code below, I was playing around with typer and dialyzer. Please take a look and let me know if you have any suggestions. </p>
<p>Thanks!<br />
  Halzy</p>
<p>[erlang]<br />
-module(frequency).<br />
-export([start/0, stop/0, allocate/0, deallocate/1, deallocate_all/0]).</p>
<p>-export([init/0]).</p>
<p>-define(SERVER, ?MODULE).</p>
<p>-type frequency() :: pos_integer().<br />
-type used_frequency() :: { frequency(), pid() }.</p>
<p>-record(state, {<br />
	  free = [] :: [frequency()],<br />
	  allocated = [] :: [used_frequency()],<br />
	  shutting_down = false :: boolean(),<br />
	  max_allocations = 3 :: pos_integer()<br />
	 }).</p>
<p>%% These are the start functions used to create and<br />
%% initialize the server.</p>
<p>start() -><br />
    register(?SERVER, spawn(?MODULE, init, [])).</p>
<p>-spec init() -> ok.<br />
init() -><br />
    State = #state{<br />
      free=get_frequencies()<br />
     },<br />
    loop(State).</p>
<p>% Hard Coded<br />
-spec get_frequencies() -> [frequency()].<br />
get_frequencies() -><br />
    [10, 11, 12, 13, 14, 15].</p>
<p>%% The client Functions</p>
<p>-spec stop() -> ok.<br />
stop() -><br />
    call(stop).</p>
<p>-spec allocate() -> {error, atom()} | pos_integer().<br />
allocate() -><br />
    call(allocate).</p>
<p>-spec deallocate(frequency()) -> ok.<br />
deallocate(Freq) -><br />
    call({deallocate, Freq}).</p>
<p>-spec deallocate_all() -> ok.<br />
deallocate_all() -><br />
    call(deallocate_all).</p>
<p>%% We hide all message passing and the message<br />
%% protocol in a functional interface</p>
<p>call(Message) -><br />
    ?SERVER ! {request, self(), Message},<br />
    receive<br />
	{reply, Reply} -><br />
	    Reply<br />
    end.</p>
<p>%% The Main Loop</p>
<p>-spec loop(#state{}) -> ok.<br />
%% [bgh] if we are shutting down, and have no outstanding frequencies, end<br />
loop(#state{shutting_down=true, allocated=[]}) -><br />
    ok;<br />
loop(#state{shutting_down=ShuttingDown}=State) -><br />
    receive<br />
	{request, Pid, allocate} when false==ShuttingDown -><br />
	    {UpdatedState, Reply} = allocate(State, Pid),<br />
	    reply(Pid, Reply),<br />
	    loop(UpdatedState);<br />
	{request, Pid, stop} when false==ShuttingDown -><br />
	    reply(Pid, ok),<br />
	    loop(State#state{shutting_down=true});<br />
	{request, Pid, {deallocate, Freq}} -><br />
	    UpdatedState = deallocate(State, Pid, Freq),<br />
	    reply(Pid, ok),<br />
	    loop(UpdatedState);<br />
	{request, Pid, deallocate_all} -><br />
	    UpdatedState = deallocate_all(State, Pid),<br />
	    reply(Pid, ok),<br />
	    loop(UpdatedState);<br />
	{request, Pid, _} when true == ShuttingDown -><br />
	    reply(Pid, {error, shutting_down}),<br />
	    loop(State)<br />
    end.</p>
<p>reply(Pid, Reply) -><br />
    Pid ! {reply, Reply}.</p>
<p>%% The Internal Help Functions used to allocate and<br />
%% deallocate frequencies.</p>
<p>-spec allocate(#state{free::[]}, pid()) -><br />
		      {#state{}, {error, no_frequency}};<br />
	      (#state{free::[frequency(),...]}, pid()) -><br />
		      {#state{}, {error, max_allocations}} |<br />
		      {#state{}, {ok, frequency()}}.<br />
allocate(#state{free=[]}=State, _Pid) -><br />
    {State, {error, no_frequency}};<br />
allocate(#state{free=[Freq|Free], allocated=Allocated}=State, Pid) -><br />
    case can_allocate(Allocated, Pid, State#state.max_allocations) of<br />
	false -><br />
	    {State, {error, max_allocations}};<br />
	true -><br />
	    {State#state{free=Free, allocated=[{Freq, Pid}|Allocated]}, {ok, Freq}}<br />
    end.</p>
<p>-spec deallocate(#state{}, pid(), frequency()) -> #state{}.<br />
deallocate(#state{free=Free, allocated=Allocated}=State, Pid, Freq) -><br />
    case lists:keytake(Freq, 1, Allocated) of<br />
	false -><br />
	    State;<br />
	{value, {Freq, Pid}, NewAllocated} -><br />
	    State#state{free=[Freq|Free], allocated=NewAllocated};<br />
	{value, {Freq, _WrongPid}, _NewAllocated} -><br />
	    State<br />
    end.</p>
<p>-spec pid_match(used_frequency(), pid()) -> boolean().<br />
pid_match({_Freq, Pid}, Pid) -> true;<br />
pid_match({_Freq, _OtherPid}, _Pid) -> false.</p>
<p>-spec deallocate_all(#state{}, pid()) -> #state{}.<br />
deallocate_all(#state{free=Free, allocated=Allocated}=State, Pid) -><br />
    {ToDeallocate, UpdatedAllocated} = lists:partition(fun(Elem) -> pid_match(Elem, Pid) end, Allocated),<br />
    {ReleasedFreqs, _Pids} = lists:unzip(ToDeallocate),<br />
    UpdatedFree = ReleasedFreqs ++ Free,<br />
    State#state{free=UpdatedFree, allocated=UpdatedAllocated}.</p>
<p>-spec can_allocate([used_frequency()], pid(), pos_integer()) -> boolean().<br />
can_allocate(Allocated, Pid, MaxFrequencies) -><br />
    {PidFrequencies, _Other} = lists:partition(fun(Elem) -> pid_match(Elem, Pid) end, Allocated),<br />
    length(PidFrequencies) < MaxFrequencies.<br />
[/erlang]</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/06/erlang-programming-exercise-5-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 5-1</title>
		<link>http://benjaminhalsted.com/2010/05/erlang-programming-exercise-5-1/</link>
		<comments>http://benjaminhalsted.com/2010/05/erlang-programming-exercise-5-1/#comments</comments>
		<pubDate>Fri, 21 May 2010 00:45:02 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=221</guid>
		<description><![CDATA[It took a while before reading chapter 5 again. I've been off trying to cobble together an Erlang replacement for some of the proxies at work. It's almost ready, it just needs to log the health stats.
When I was reading through the "Programming Erlang" book by Joe Armstrong I ended up doing an exercise very [...]]]></description>
			<content:encoded><![CDATA[<p>It took a while before reading chapter 5 again. I've been off trying to cobble together an Erlang replacement for some of the proxies at work. It's almost ready, it just needs to log the health stats.</p>
<p>When I was reading through the "Programming Erlang" book by Joe Armstrong I ended up doing an exercise very much like <a href="http://benjaminhalsted.com/2010/03/erlang-programming-exercise-3-4/">Exercise 3-4</a>, but I made a mistake and implemented it as a server, like this exercise. It's fun to compare my styles. In the last version I had a large case statement for the different actions I wanted to do, and each option called a function of the same action name. I'm understanding the behavior design patterns better now and it results in less code written.</p>
<p>In my implementation (below) I used the lists module as much as I could, the one exception being the match function. I couldn't find a lists function that would work. I thought about using lists:filter/2, but that would result in more code because I'd have to write the predicate function and then pull the keys out of the resulting list of tuples.</p>
<p>Since my last post I've also watched all of the <a href="http://www.pragprog.com/screencasts/v-kserl/erlang-in-practice">Erlang in Practice</a> videos by Kevin Smith. I liked his use of ?SERVER versus ?MODULE when spawning processes and sending messages. He has 5 hours worth of video in 8 screencasts. I highly recommend them to other Erlang noobs out there.</p>
<p>Most of the exercise was straight forward. I had to look up in the man pages the lists, spawn/3 and register/2 function calls. The part that I had the biggest problem with was the spawn call interacting with the init call. I didn't realize that if I wanted to pass an empty array to the init call I had to put it inside the arguments array like so: [[]]. My first attempt was without the inner array and it would crash at runtime. It makes sense now. It is an array of arguments. If you give it an empty array, then there are no arguments and it will look for init/0 instead of init/1.</p>
<p>And the implementation:<br />
[erlang]<br />
-module(my_db).<br />
-export([start/0, stop/0, write/2, delete/1, read/1, match/1]).<br />
-export([init/1, terminate/1]).</p>
<p>-define(SERVER, ?MODULE).</p>
<p>%% [bgh] PUBLIC INTERFACE</p>
<p>start() -><br />
    register(?SERVER, spawn(my_db, init, [[]])),<br />
    ok.</p>
<p>stop() -><br />
    ?SERVER ! {stop, self()},<br />
    receive<br />
	{reply, Reply} -><br />
	    Reply<br />
    end.</p>
<p>write(Key, Element) -><br />
    call(?SERVER, {write, Key, Element}).</p>
<p>delete(Key) -><br />
    call(?SERVER, {delete, Key}).</p>
<p>read(Key) -><br />
    call(?SERVER, {read, Key}).</p>
<p>match(Element) -><br />
    call(?SERVER, {match, Element}).</p>
<p>%% [bgh] start/stop interface</p>
<p>init(Args) -><br />
    loop(Args).</p>
<p>terminate(State) -><br />
    State.</p>
<p>%% [bgh] server handler functions<br />
handle_msg({write, Key, Element}, Db) -><br />
    {ok, lists:keystore(Key, 1, Db, {Key, Element})};<br />
handle_msg({delete, Key}, Db) -><br />
    {ok, lists:keydelete(Key, 1, Db)};<br />
handle_msg({read, Key}, Db) -><br />
    case lists:keyfind(Key, 1, Db) of<br />
	false -><br />
	    {{error, instance}, Db};<br />
	{Key, Value} -><br />
	    {{ok, Value}, Db}<br />
    end;<br />
handle_msg({match, Value}, Db) -><br />
    {match(Value, Db), Db}.</p>
<p>match(_Element, [], Keys) -><br />
        Keys;<br />
match(Element, [{Key,Element}|Db], Keys) -><br />
        match(Element, Db, [Key|Keys]);<br />
match(Element, [_H|Db], Keys) -><br />
        match(Element, Db, Keys).</p>
<p>match(Element, Db) -><br />
        match(Element, Db, []).</p>
<p>%% [bgh] copy/pasted from page 135, erlang programming<br />
call(Name, Msg) -><br />
    Name ! {request, self(), Msg},<br />
    receive {reply, Reply} -> Reply end.<br />
reply(To, Msg) -><br />
    To ! {reply, Msg}.<br />
loop(State) -><br />
    receive<br />
	{request, From, Msg} -><br />
	    {Reply, NewState} = handle_msg(Msg, State),<br />
	    reply(From, Reply),<br />
	    loop(NewState);<br />
	{stop, From} -><br />
	    reply(From, terminate(State))<br />
    end.<br />
[/erlang]</p>
<p>Cheers,<br />
  Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/05/erlang-programming-exercise-5-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silence</title>
		<link>http://benjaminhalsted.com/2010/05/silence/</link>
		<comments>http://benjaminhalsted.com/2010/05/silence/#comments</comments>
		<pubDate>Thu, 13 May 2010 14:49:19 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/2010/05/silence/</guid>
		<description><![CDATA[The blog has been a bit quiet. I've been rewriting some of our server software at work in Erlang and it's taken up most of my free time. I'm about done with it, so we should see the posts pick up again soon.
Cheers,
  Halzy
]]></description>
			<content:encoded><![CDATA[<p>The blog has been a bit quiet. I've been rewriting some of our server software at work in Erlang and it's taken up most of my free time. I'm about done with it, so we should see the posts pick up again soon.</p>
<p>Cheers,<br />
  Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/05/silence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 4-2</title>
		<link>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-4-2/</link>
		<comments>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-4-2/#comments</comments>
		<pubDate>Wed, 28 Apr 2010 00:32:57 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=199</guid>
		<description><![CDATA[I've finished with the process ring. I've done this exercise once before when reading "Programming Erlang". Last time I had the processes create each other and set up the connections, this time they were created and linked by the start function. The code is much cleaner this time around. 
The basic idea is that you [...]]]></description>
			<content:encoded><![CDATA[<p>I've finished with the process ring. I've done this exercise once before when reading "Programming Erlang". Last time I had the processes create each other and set up the connections, this time they were created and linked by the start function. The code is much cleaner this time around. </p>
<p>The basic idea is that you create a number of processes and each process knows the process id of it's neighbor in the ring. When a process receives a message, it should forward it on to it's neighbor. You then send X number of messages into the ring and watch your laptop turn into a skillet. </p>
<p>Please review the code and let me know if you have any suggestions.<br />
[erlang]<br />
-module(four_two).</p>
<p>-export([start/3, test/0]).<br />
-export([process_loop/0, process_loop/1]).</p>
<p>test() -><br />
    FirstPid = start(10,4,"This is a message"),</p>
<p>    %% [bgh] after 15 second, kill it automatically<br />
    receive<br />
    after<br />
	15000 -><br />
	    stop(FirstPid)<br />
    end.</p>
<p>stop(Pid) -><br />
    Pid ! {stop, 0}.</p>
<p>start(M, N, Message) -><br />
    %% [bgh] start N processes<br />
    Pids = lists:reverse(lists:foldl(<br />
				   fun(_Number,PidList) -><br />
					   NewPid = spawn(?MODULE, process_loop, []),<br />
					   [NewPid|PidList]<br />
				   end,<br />
				   [],<br />
				   lists:seq(1, N)<br />
				 )),</p>
<p>    %% [bgh] Shift the one off the front, and put it on the end<br />
    NeighborPids = rotate_array(Pids),</p>
<p>    %% [bgh] link the N processes together<br />
    link_pids(Pids, NeighborPids),</p>
<p>    [FirstPid|_OtherPids] = Pids,</p>
<p>    %% [bgh] start the message sending by sending M messages to PID<br />
    send_messages_to_pid(M, Message, FirstPid),</p>
<p>    %% [bgh] start the processes sending messages<br />
    FirstPid.</p>
<p>rotate_array([]) -><br />
    [];<br />
rotate_array([First|_]=List) when length(List) =:= 1 -><br />
    [First];<br />
rotate_array([First|Remainder]) -><br />
    io:format("~p ~p~n", [First,Remainder]),<br />
    lists:append(Remainder,[First]).</p>
<p>send_messages_to_pid(M, Message, FirstPid) when M > 0 -><br />
    FirstPid ! {message, Message},<br />
    send_messages_to_pid(M-1, Message, FirstPid);<br />
send_messages_to_pid(_M, _Message, _FirstPid) -><br />
    ok.</p>
<p>link_pids([], []) -><br />
    ok;<br />
link_pids([Pid|Pids], [NPid|NeighborPids]) -><br />
    Pid ! {link, NPid},<br />
    link_pids(Pids, NeighborPids).</p>
<p>process_loop() -><br />
    receive<br />
	{link, Pid} -><br />
	    process_loop({Pid, 0});<br />
	Other -><br />
	    io:format("Ignored ~p~n", [Other]),<br />
	    process_loop()<br />
    end.</p>
<p>process_loop({Pid, Count}) -><br />
    receive<br />
	{message, Message} -><br />
	    Pid ! {message, Message},<br />
	    process_loop({Pid, Count+1});<br />
	{stop, CountSum} -><br />
	    Pid ! {stop, Count+CountSum},<br />
	    io:format("~p is shutting down, saw ~p messages~n", [self(), Count+CountSum]);<br />
	Other -><br />
	    io:format("Ignored ~p~n", [Other]),<br />
	    process_loop({Pid, Count})<br />
    end.<br />
[/erlang]</p>
<p>Cheers,<br />
  Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-4-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 4-1</title>
		<link>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-4-1/</link>
		<comments>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-4-1/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 15:41:17 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=195</guid>
		<description><![CDATA[I'm glad to be past chapter 3, and that I took the time to go through the exercises. I would highly suggest to anybody learning Erlang to do the same. They helped me learn the syntax of the language and to become much more comfortable in Erlang. I also found the erlang man pages to [...]]]></description>
			<content:encoded><![CDATA[<p>I'm glad to be past chapter 3, and that I took the time to go through the exercises. I would highly suggest to anybody learning Erlang to do the same. They helped me learn the syntax of the language and to become much more comfortable in Erlang. I also found the erlang man pages to be very helpful. For example, to get the full documentation for the lists module you type "erl -man lists" in a shell.</p>
<p>Before jumping into the exercises for chapter four I went back and re-read the chapter. It's a nice reminder of how Erlang is different from the languages I use for work. I'm still having trouble trying to grok the activity vs task mentality, it's so different from what I'm used to.</p>
<p>Exercise 4-1 I found to be much easier than 3-10. The goal is to start up a process that prints out messages you send to it, but to have the interaction with that process through a public interface. </p>
<p>Here is the interface you are supposed to maintain:<br />
[erlang]<br />
echo:start() ⇒ ok<br />
echo:print(Term) ⇒ ok<br />
echo:stop() ⇒ ok<br />
[/erlang]</p>
<p>Since I've been naming my modules after the exercise chapter and number I changed 'echo' to four_one. Here is my solution:</p>
<p>[erlang]<br />
-module(four_one).<br />
-export([start/0,print/1,stop/0]).</p>
<p>-export([loop/0]).</p>
<p>start() -><br />
	Pid = spawn(four_one,loop,[]),<br />
	register(four_one, Pid),<br />
	ok.</p>
<p>print(Term) -><br />
	four_one ! {print, Term},<br />
	ok.</p>
<p>stop() -><br />
	four_one ! stop,<br />
	ok.</p>
<p>loop() -><br />
	receive<br />
		stop -> ok;<br />
		{print, Term} -><br />
			io:format("~p~n", [Term]),<br />
			loop()<br />
	end.<br />
[/erlang]</p>
<p>Cheers,<br />
  Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-4-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 3-10</title>
		<link>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-10/</link>
		<comments>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-10/#comments</comments>
		<pubDate>Wed, 21 Apr 2010 02:06:14 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=190</guid>
		<description><![CDATA[Exercise 3-10 has you take unstructured text and make filled text, then later, justified text. 
Now, it's trivial to justify the text, you could even do it in a single pass, but I wanted to solve both the filled text and the text justification at the same time. To make development faster, I wrote some [...]]]></description>
			<content:encoded><![CDATA[<p>Exercise 3-10 has you take unstructured text and make filled text, then later, justified text. </p>
<p>Now, it's trivial to justify the text, you could even do it in a single pass, but I wanted to solve both the filled text and the text justification at the same time. To make development faster, I wrote some test stubs (at the bottom of the file) that would load the text from disk, and call the interface functions. </p>
<p>textProcess and justifyText do basically the same thing, with justifyText trying to figure out how many extra spaces to put in each gap. They start out by creating a list of tuples of {Word, WordLength} and then passing that list into makeWordLines/4 which builds lines. At this point, passing the lines into wordLinesToString/2 will solve the filled text part of the problem. To solve the justified text part, the lines are passed into justifyWordLines/2 which will calculate how many extra spaces per gap are needed and call wordLineToString/5 to turn the line into a string.</p>
<p>My implementation suffers from floating point arithmetic problems. Some lines will not get the last space in the last gap because the gap value is 0.999999999999 instead of 1. <img src='http://benjaminhalsted.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  This could be solved in a couple of ways, but I'm ready to move into chapter 4.</p>
<p>Looking at the code now, it's very verbose and can probably be done more succinctly.<br />
[erlang]<br />
-module(threeten).<br />
-export([textProcess/2, justifyText/2, testProcess/1, testJustify/1]).</p>
<p>textProcess(Text, Width) -><br />
	TokenText = tokenizeText(Text),<br />
	WordLines = makeWordLines(TokenText, Width, Width, []),<br />
	wordLinesToString(WordLines).</p>
<p>justifyText(Text, Width) -><br />
	TokenText = tokenizeText(Text),<br />
	WordLines = makeWordLines(TokenText, Width, Width, []),<br />
	justifyWordLines(WordLines, Width).</p>
<p>justifyWordLines(WordLines, Width) -><br />
	justifyWordLines(WordLines, Width, []).</p>
<p>justifyWordLines([], _Width, JustifiedLines) -><br />
	lists:flatten(lists:reverse(JustifiedLines));<br />
justifyWordLines([[]|WordLines], Width, JustifiedLines) -><br />
	justifyWordLines(WordLines, Width, JustifiedLines);<br />
justifyWordLines([Line|WordLines], Width, JustifiedLines) -><br />
	SpacesPerGap = case length(WordLines) of<br />
		0 -> 0; % the last line isn't justified<br />
		_Other -> spacesPerGap(Line, Width)<br />
	end,<br />
	JustifiedString = lists:reverse(wordLineToString(Line, 0, "", SpacesPerGap, 0)),<br />
	justifyWordLines(WordLines, Width, [JustifiedString|JustifiedLines]).</p>
<p>spacesPerGap([], _Width) -><br />
	0;<br />
spacesPerGap(Line, Width) -><br />
	Words = length(Line),<br />
	WordLength = lists:foldr(fun({_Word, Length}, Accum) -> Length + Accum end, 0, Line),<br />
	ExtraSpaces = Width - WordLength - Words + 1,<br />
	Gaps = Words-1,<br />
	if<br />
		Gaps =< 0 -> 0;<br />
		ExtraSpaces =< 0 -> 0;<br />
		ExtraSpaces > 0 -> ExtraSpaces / Gaps<br />
	end.</p>
<p>wordLinesToString(WordLines) -><br />
	lists:flatten(wordLinesToString(WordLines, [])).</p>
<p>wordLinesToString([], Strings) -><br />
	lists:reverse(Strings);<br />
wordLinesToString([[]|WordLines], String) -><br />
	wordLinesToString(WordLines, String);<br />
wordLinesToString([Line|WordLines], String1) -><br />
	String2 = wordLineToString(Line, 0, String1, 0, 0),<br />
	wordLinesToString(WordLines, String2).</p>
<p>wordLineToString([], _WordNumber, String, _SpacesPerGap, _GapLeftover) -><br />
	NewLine = "\n",<br />
	[NewLine|String];<br />
wordLineToString([{Word, _Length}|Line], WordNumber, String, SpacesPerGap, _GapLeftover) when WordNumber == 0 -><br />
	wordLineToString(Line, WordNumber+1, [Word|String], SpacesPerGap, SpacesPerGap);<br />
wordLineToString([{Word1, _Length}|Line], WordNumber1, String, SpacesPerGap, GapLeftover1) -><br />
	WordNumber2 = WordNumber1+1,				% figure out the current word number<br />
	Spaces = erlang:trunc(GapLeftover1)		,	% drop the decimal places<br />
	GapLeftover2 = GapLeftover1 - Spaces + SpacesPerGap,	% adjust the remaining leftover<br />
	Word2 = [string:copies(" ", Spaces+1)|Word1],<br />
	wordLineToString(Line, WordNumber2, [Word2|String], SpacesPerGap, GapLeftover2).</p>
<p>% end case, out of words<br />
makeWordLines([], _Width, _WidthLeft, [LastLine|Lines]) -><br />
	ReversedLastLine = lists:reverse(LastLine),<br />
	AllLines = [ReversedLastLine|Lines],<br />
	lists:reverse(AllLines);<br />
% if the line is currently empty, and the word length is =< than the length of the line<br />
makeWordLines([{_Word, Length}=Token|Tokens], Width, WidthLeft, [[]|Lines]) when Length =< Width -><br />
	makeWordLines(Tokens, Width, WidthLeft-Length, [[Token]|Lines]);<br />
% line with words, and the word length is =< the length left<br />
makeWordLines([{_Word, Length}=Token|Tokens], Width, WidthLeft, [LastLine|Lines]) when Length < WidthLeft -><br />
	makeWordLines(Tokens, Width, WidthLeft-Length-1, [[Token|LastLine]|Lines]);<br />
% if the line is empty, and the word length is > the width of the line<br />
makeWordLines([{_Word, Length}=Token|Tokens], Width, _WidthLeft, [[]|Lines]) when Length > Width -><br />
	makeWordLines(Tokens, Width, 0, [[Token]|Lines]);<br />
% if there is no more space on the line, reverse the tokens on the last line and push a new one on the stack<br />
makeWordLines(Tokens, Width, _WidthLeft, [LastLine|Lines]) -><br />
	ReversedLastLine = lists:reverse(LastLine),<br />
	PreviousLines = [ReversedLastLine|Lines],<br />
	makeWordLines(Tokens, Width, Width, [[]|PreviousLines]);<br />
% initial case where we have no existing lines on the stack<br />
makeWordLines(Tokens, Width, WidthLeft, []) -><br />
	makeWordLines(Tokens, Width, WidthLeft, [[]]).</p>
<p>tokenizeText(Text) -><br />
	Tokens = string:tokens(Text, " \t\r\n"),<br />
	measureTokens([], Tokens).</p>
<p>measureTokens(Measured, []) -><br />
	lists:reverse(Measured);<br />
measureTokens(Measured, [Token|Tokens]) -><br />
	Length = string:len(Token),<br />
	measureTokens([{Token, Length}|Measured], Tokens).</p>
<p>%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%<br />
%% Loading Test Stubs %%%%%%%%%%%%%%%%%%%%%%<br />
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%</p>
<p>testProcess(Width) -><br />
	{ok, Text} = readFileText('threeten.text'),<br />
	io:format("~s~n", [textProcess(Text, Width)]).<br />
testJustify(Width) -><br />
	{ok, Text} = readFileText('threeten.text'),<br />
	io:format("~s~n", [justifyText(Text, Width)]).</p>
<p>readFileText(Filename) -><br />
        case file:open(Filename, read) of<br />
                {ok, IoDevice} -><br />
                        Words = loadRawTextLines([], IoDevice),<br />
                        file:close(IoDevice),<br />
			{ok, Words};<br />
                {error, Reason} -> {error, Reason}<br />
        end.</p>
<p>loadRawTextLines(Lines, IoDevice) -><br />
        case file:read_line(IoDevice) of<br />
		{ok, Line} -> loadRawTextLines([Line|Lines], IoDevice);<br />
                eof -> lists:flatten(lists:reverse(Lines))<br />
        end.<br />
[/erlang]</p>
<p>Cheers,<br />
  Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-10/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 3-9</title>
		<link>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-9/</link>
		<comments>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-9/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 15:18:58 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=182</guid>
		<description><![CDATA[In exercise three-nine you are to read some text into a raw document (list of lines) and then into a document (list of words). With this data you generate an index for the words to which lines they were on:
{ "Erlang", [1,1,2,4,5,6,6,98,100,102,102] }
After you have the word to line index, pretty print the index such [...]]]></description>
			<content:encoded><![CDATA[<p>In exercise three-nine you are to read some text into a <em>raw document</em> (list of lines) and then into a <em>document</em> (list of words). With this data you generate an index for the words to which lines they were on:</p>
<p style="padding-left: 30px;">{ "Erlang", [1,1,2,4,5,6,6,98,100,102,102] }</p>
<p>After you have the word to line index, pretty print the index such that the example above would result in:</p>
<p style="padding-left: 30px;">"Erlang 1-2,4-6,98,100,102"</p>
<p>I decided to start using more of the library functions in order to become more familiar with them. I used the lists/foldr function more than anything else since it lets you visit every element in a list and maintain an accumulator. It was particularly useful in situations where I didn't want to do any pattern matching on the argument, like when I broke the lines into words. It was not useful when I tried to generate the tuples needed for the pretty printed line numbers, this could have been done using a switch statement but I found the code more elegant using the recursive pattern matching. </p>
<p>Instead of copy/pasting a chunk of text into erl every time I wanted to test it, I made the indexer load a file from disk. I also aligned the line numbers, having them all start on the same column made a big difference visually. Here's an example run:</p>
<p>[shell]<br />
1> threenine:index("./threenine.erl").<br />
0                          70<br />
1                          2, 30, 32, 37, 41, 57, 80<br />
2                          64<br />
binary                     77<br />
bs                         71<br />
case                       5, 22, 37<br />
cleannumbers               46, 51-60<br />
close                      8, 14<br />
concat                     87-88<br />
...<br />
updatedlinenumbers         46-47<br />
updatedwordindex           41-42<br />
updatewordindexlinenumbers 17, 44<br />
when                       57<br />
[/shell]</p>
<p>Here is the code:</p>
<p>[erlang]<br />
-module(threenine).<br />
-export([index/1]).</p>
<p>index(Filename) -><br />
	case file:open(Filename, read) of<br />
		{ok, IoDevice} -><br />
			indexFile(IoDevice),<br />
			file:close(IoDevice);<br />
		{error, Reason} -> {error, Reason}<br />
	end.</p>
<p>indexFile(IoDevice) -><br />
	RawDocument = loadRawDocument([], IoDevice),<br />
	file:close(IoDevice),<br />
	Document = loadDocument(RawDocument),<br />
	WordIndex1 = indexWords(Document),<br />
	WordIndex2 = updateWordIndexLineNumbers(WordIndex1),<br />
	prettyPrintWordIndex(WordIndex2),<br />
	ok.</p>
<p>loadRawDocument(Lines, IoDevice) -><br />
	case file:read_line(IoDevice) of<br />
		{ok, Line} -> loadRawDocument([Line|Lines], IoDevice);<br />
		eof -> lists:reverse(Lines)<br />
	end.</p>
<p>loadDocument(RawDocument) -><br />
	MakeDoc = fun(Line, {LineNo, Document}) -><br />
		Tokens = string:tokens(Line, "\r\n\t {,}->:;[]().|\\=/~\"'+_"),<br />
		{LineNo+1, [{LineNo, Tokens}|Document]}<br />
	end,<br />
	{_LineNumber, Document} = lists:foldl(MakeDoc, {1, []}, RawDocument),<br />
	lists:reverse(Document).</p>
<p>indexWordsFun(Word, {LineNo, WordIndex}) -><br />
	LowerWord = string:to_lower(Word),<br />
	LineNumbersList = case lists:keyfind(LowerWord, 1, WordIndex) of<br />
		{LowerWord, LineNumbers} -> LineNumbers;<br />
		false -> []<br />
	end,<br />
	UpdatedWordIndex = lists:keystore(LowerWord, 1, WordIndex, {LowerWord, [LineNo|LineNumbersList]}),<br />
	{LineNo, UpdatedWordIndex}.</p>
<p>updateWordIndexLineNumbers(WordIndex) -><br />
	Update = fun({Word, LineNumbers}, NewWordIndex) -><br />
		UpdatedLineNumbers = cleanNumbers(LineNumbers, []),<br />
		[{Word, UpdatedLineNumbers}|NewWordIndex]<br />
	end,<br />
	lists:foldr(Update, [], WordIndex).</p>
<p>cleanNumbers([], CleanNumbers) -><br />
	CleanNumbers;<br />
cleanNumbers([Number|LineNumbers], []) -><br />
	cleanNumbers(LineNumbers, [{Number, Number}]);<br />
cleanNumbers([Number|LineNumbers], [{_Start, Number}|_Tail]=NewNumbers) -><br />
	cleanNumbers(LineNumbers, NewNumbers);<br />
cleanNumbers([Number|LineNumbers], [{Start, End}|Tail]) when Number == End+1 -><br />
	cleanNumbers(LineNumbers, [{Start, Number}|Tail]);<br />
cleanNumbers([Number|LineNumbers], NewNumbers) -><br />
	cleanNumbers(LineNumbers, [{Number, Number}|NewNumbers]).</p>
<p>indexWords(Document) -><br />
	IndexWords = fun({LineNo, Words}, WordIndex) -><br />
		{LineNo, WordIndex2} = lists:foldr(fun indexWordsFun/2, {LineNo, WordIndex}, Words),<br />
		WordIndex2<br />
	end,<br />
	lists:foldr(IndexWords, [], Document).</p>
<p>makePrintFormat(WordIndex) -><br />
	MaxLength = lists:foldr(fun({Word,_Lines}, Max) -> erlang:max(string:len(Word), Max) end, 0, WordIndex),<br />
	io_lib:format("~~-~Bs ~~s~~n", [MaxLength]).</p>
<p>prettyPrintWordIndex(WordIndex) -><br />
	PrintFormat = makePrintFormat(WordIndex),<br />
	PrintWord = fun({Word, LineNumbers}, Format) -><br />
		PrettyLineNumbers = makePrettyLineNumbers(LineNumbers),<br />
		io:format(list_to_binary(PrintFormat), [Word, PrettyLineNumbers]),<br />
		Format<br />
	end,<br />
	lists:foldr(PrintWord, PrintFormat, lists:reverse(lists:keysort(1,WordIndex))).</p>
<p>getPrettyLineNumbers(Result, []) -><br />
	Result;<br />
getPrettyLineNumbers(Result, [{Number,Number}|LineNumbers]) -><br />
	getPrettyLineNumbers([integer_to_list(Number)|Result], LineNumbers);<br />
getPrettyLineNumbers(Result, [{Start,End}|LineNumbers]) -><br />
	Range1=string:concat(integer_to_list(Start), "-"),<br />
	Range2=string:concat(Range1, integer_to_list(End)),<br />
	getPrettyLineNumbers([Range2|Result], LineNumbers).</p>
<p>makePrettyLineNumbers(LineNumbers) -><br />
	RangedLineNumbers = getPrettyLineNumbers([], LineNumbers),<br />
	string:join(RangedLineNumbers, ", ").<br />
[/erlang]</p>
<p>Cheers,<br />
 -Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 3-8-4 &amp; 3-8-5</title>
		<link>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-8-4-3-8-5/</link>
		<comments>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-8-4-3-8-5/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 14:33:43 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=180</guid>
		<description><![CDATA[I enjoyed coding up 3-8-4 and 3-8-5. It took just a couple hours to finish the pair. In the first one you implement a compiler for a stack machine, in the second you implement the stack machine. There is a lot to think about. How does a stack machine work? What will you be generating? [...]]]></description>
			<content:encoded><![CDATA[<p>I enjoyed coding up 3-8-4 and 3-8-5. It took just a couple hours to finish the pair. In the first one you implement a compiler for a stack machine, in the second you implement the stack machine. There is a lot to think about. How does a stack machine work? What will you be generating? How do the instructions for (3+4)+5 differ from 3+(4+5)? How will the stack machine differ from the evaluator in 3-8-2?</p>
<p>Starting out I looked up <a href="http://en.wikipedia.org/wiki/Stack_machine">stack machine on Wikipedia</a> and found a link to <a href="http://en.wikipedia.org/wiki/Instruction_set#Number_of_operands">"0-operand" instruction sets</a> that had enough information for me to get going. I decided to keep all of my instructions one token long for simplicity. I have 'add' and 'sub' which use the first two arguments off of the stack, 'umin' (unary minus) only uses the the first item off of the stack. I don't have a need for a 'pop' instruction and decided that 'push' was the default. As an example, adding 1+2 would look like: [1, 2, add]. The numbers would get pushed onto the stack, and then add would take the first two items off of the stack, add them together and place the results back onto the stack.</p>
<p>I may at a later time go back and change the instruction set to have proper push and pop instructions, but for now, this worked.</p>
<p>[erlang]<br />
-module(threeeightyfour).<br />
-export([compile/1]).</p>
<p>translateInstruction(unary_minus) -> umin;<br />
translateInstruction(minus) -> sub;<br />
translateInstruction(plus) -> add.</p>
<p>compileExpression(Instructions, []) -><br />
	Instructions;</p>
<p>compileExpression(Instructions, [{num, Value}|Expressions]) -><br />
	compileExpression([Value|Instructions], Expressions);</p>
<p>compileExpression(Instructions, [{Operator, Value}|Expressions]) -><br />
	Op = translateInstruction(Operator),<br />
	OpInstructions = [Op|Instructions],<br />
	ValueExp = [Value|Expressions],<br />
	compileExpression(OpInstructions, ValueExp);</p>
<p>compileExpression(Instructions, [{Operator, LHS, RHS}|Expressions]) -><br />
	Op = translateInstruction(Operator),<br />
	OpInstructions = [Op|Instructions],<br />
	RightExp = [RHS|Expressions],<br />
	LeftExp = [LHS|RightExp],<br />
	compileExpression(OpInstructions, LeftExp).</p>
<p>compileExpression(Expression) -><br />
	compileExpression([], [Expression]).</p>
<p>compile(Results, []) -><br />
	lists:reverse(Results);<br />
compile(Results, [CurrentExpression|Expressions]) -><br />
	Result = compileExpression(CurrentExpression),<br />
	compile([Result|Results], Expressions).</p>
<p>compile(Expressions) -><br />
	compile([], Expressions).<br />
[/erlang]</p>
<p>And the stack simulator:<br />
[erlang]<br />
-module(threeeightyfive).<br />
-export([simulate/1]).</p>
<p>simulator([Value|_Stack], []) -><br />
	Value;<br />
simulator([Value|Stack], [umin|Instructions]) -><br />
	UminValue = -1 * Value,<br />
	simulator([UminValue|Stack], Instructions);<br />
simulator([FirstValue|Stack], [sub|Instructions]) -><br />
	[SecondValue|MoreStack] = Stack,<br />
	simulator([FirstValue - SecondValue|MoreStack], Instructions);<br />
simulator([FirstValue|Stack], [add|Instructions]) -><br />
	[SecondValue|MoreStack] = Stack,<br />
	simulator([FirstValue + SecondValue|MoreStack], Instructions);<br />
simulator(Stack, [Number|Instructions]) -><br />
	simulator([Number|Stack], Instructions).</p>
<p>simulator(Instructions) -><br />
	simulator([], Instructions).</p>
<p>simulate(Results, []) -><br />
	lists:reverse(Results);<br />
simulate(Results, [Instructions|ArraysOfInstructions]) -><br />
	Result = simulator(Instructions),<br />
	simulate([Result|Results], ArraysOfInstructions).</p>
<p>simulate(ArraysOfInstructions) -><br />
	simulate([], ArraysOfInstructions).<br />
[/erlang]</p>
<p>Cheers,<br />
 -Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-8-4-3-8-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 3-8-3</title>
		<link>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-8-3/</link>
		<comments>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-8-3/#comments</comments>
		<pubDate>Thu, 01 Apr 2010 07:00:34 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=168</guid>
		<description><![CDATA[This exercise is similar to the last one. But instead of evaluating the expressions, we pretty-print them.
I had trouble trying to figure out the right way to append data to a string. I probably could have used plain old list manipulation, building the strings in reverse as I went along, and then reversing them before [...]]]></description>
			<content:encoded><![CDATA[<p>This exercise is similar to the last one. But instead of evaluating the expressions, we pretty-print them.</p>
<p>I had trouble trying to figure out the right way to append data to a string. I probably could have used plain old list manipulation, building the strings in reverse as I went along, and then reversing them before they returned, but I opted to try out some functions in the string module.</p>
<p>[erlang]<br />
-module(threeeightythree).<br />
-export([print/1]).</p>
<p>addParens(String) -><br />
	A = string:concat([$(], String),<br />
	string:concat(A, [$)]).</p>
<p>prettyPrintDoubleOperator(Op, LHS, RHS) -><br />
	A = string:concat(prettyPrint(LHS), [Op]),<br />
	B = string:concat(A, prettyPrint(RHS)),<br />
	addParens(B).</p>
<p>prettyPrintSingleOperator(Op, Expression) -><br />
	A = string:concat([Op], prettyPrint(Expression)),<br />
	addParens(A).</p>
<p>prettyPrint({plus, LHS, RHS}) -><br />
	prettyPrintDoubleOperator($+, LHS, RHS);<br />
prettyPrint({minus, LHS, RHS}) -><br />
	prettyPrintDoubleOperator($-, LHS, RHS);<br />
prettyPrint({unary_minus, Expression}) -><br />
	prettyPrintSingleOperator($~, Expression);<br />
prettyPrint({num, Number}) -><br />
	[Number + 48].</p>
<p>pretty(Results, []) -><br />
	lists:reverse(Results);<br />
pretty(Results, [Expression|List]) -><br />
	Result = prettyPrint(Expression),<br />
	pretty([Result|Results], List).<br />
print(Expressions) -><br />
	pretty([], Expressions).<br />
[/erlang]</p>
<p>Here is an example run. This time using unary minus!</p>
<p>[shell]<br />
1> T83 = threeeightyone:parser("((2+3)+(4+(5+6)))~7~(8+9)").<br />
[{plus,{plus,{num,2},{num,3}},{plus,{num,4},{plus,{num,5},{num,6}}}},<br />
 {unary_minus,{num,7}},<br />
 {unary_minus,{plus,{num,8},{num,9}}}]<br />
2> threeeightythree:print(T83).<br />
["((2+3)+(4+(5+6)))","(~7)","(~(8+9))"]<br />
[/shell]</p>
<p>You'll notice some extra parenthesis. I could have been more selective with them but decided that for simplicity they would be everywhere. <img src='http://benjaminhalsted.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Cheers,<br />
  Ben</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/04/erlang-programming-exercise-3-8-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang Programming Exercise: 3-8-2</title>
		<link>http://benjaminhalsted.com/2010/03/erlang-programming-exercise-3-8-2/</link>
		<comments>http://benjaminhalsted.com/2010/03/erlang-programming-exercise-3-8-2/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 07:00:23 +0000</pubDate>
		<dc:creator>halzy</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[exercise]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://benjaminhalsted.com/?p=158</guid>
		<description><![CDATA[For exercise 3-8-2 we are to create an evaluator. It should take the output (expressions) from 3-8-1 and returns its value. And to make the code a little bit easier to read, LHS and RHS are the left hand and right hand side of the expressions.
[erlang]
-module(threeeightytwo).
-export([evaluator/1]).
evaluate({plus, LHS, RHS}) ->
       [...]]]></description>
			<content:encoded><![CDATA[<p>For exercise 3-8-2 we are to create an evaluator. It should take the output (expressions) from 3-8-1 and returns its value. And to make the code a little bit easier to read, LHS and RHS are the left hand and right hand side of the expressions.</p>
<p>[erlang]<br />
-module(threeeightytwo).<br />
-export([evaluator/1]).</p>
<p>evaluate({plus, LHS, RHS}) -><br />
        evaluate(LHS) + evaluate(RHS);<br />
evaluate({minus, LHS, RHS}) -><br />
        evaluate(LHS) - evaluate(RHS);<br />
evaluate({unary_minus, Expression}) -><br />
        -1 * evaluate(Expression);<br />
evaluate({num, Number}) -><br />
        Number.</p>
<p>eval(Results, []) -><br />
        lists:reverse(Results);<br />
eval(Results, [Expression|List]) -><br />
        Result = evaluate(Expression),<br />
        eval([Result|Results], List).</p>
<p>evaluator(Expressions) -><br />
        eval([], Expressions).<br />
[/erlang]</p>
<p>As you can see I return an array of results. This is because the return value from my 3-8-1 returns an array of expressions. Here is an example run:</p>
<p>[shell]<br />
1> T81 = threeeightyone:parser("((2+3)+(4+(5+6)))7(8+9)").<br />
[{plus,{plus,{num,2},{num,3}},{plus,{num,4},{plus,{num,5},{num,6}}}},<br />
 {num,7},<br />
 {plus,{num,8},{num,9}}]<br />
2> threeeightytwo:evaluator(T81).<br />
[20,7,17]<br />
[/shell]</p>
<p>I have three expressions as the argument to 3-8-1:</p>
<ol>
<li>((2+3)+(4+(5+6)))</li>
<li>7</li>
<li>(8+9)</li>
</ol>
<p>And there are three values as the result from 3-8-2:</p>
<ol>
<li>20</li>
<li>7</li>
<li>17</li>
</ol>
<p>And we double check the results. Looks good!</p>
<p>Cheers,<br />
 -Halzy</p>
]]></content:encoded>
			<wfw:commentRss>http://benjaminhalsted.com/2010/03/erlang-programming-exercise-3-8-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
