solutions to programming erlang

I pickup languages willy nilly. I find I can learn enough to use them quite fast. This year I've written a few 1000 lines of Go and D without really trying very hard to learn either language. I also quite like reading programming language books. I've read books on Go and D this year.

Another programming book I brought this year was Joe Armstrong's Programming Erlang. It's a good book. So I decided I would use it to learn Erlang properly as Joe seems to intend (note, I've picked Erlang up enough to use it and forgotten it several times in the last 15 years).

One of the things Joe does is give you exercises at the end of every chapter. When I was 25 I used to hate these because it reminded me of school. But now memories of school are dimmed (though not enough to go on fondly about how they were the best days of my life, you must be a total amnesiac to think that, surely). Anyway, I'm rambling. Here are my answers to his exercises.

I hope people will tweet criticisms of them @nicferrier and tell me how to write better erlang.

Chapter 4 question 1

Extend gemoetry.erl:


area({rectangle, Width, Height}) -> Width * Height;
area({square, Side}) -> Side * Side;

% exercises from @joerl's book chapter 4
area({circle, Radius}) -> 3.141579*Radius;
area({triangle, Width, Height}) -> (Width*Height) / 2.

% end.

this is too simple for me to have done it badly, surely?

Chapter 4, question 2

Make your own tuple_to_list:

% for @joerl book chapter 4

my_tuple_to_list({ Atom, Tuple }) -> [Atom, Tuple];
my_tuple_to_list({}) -> [];
my_tuple_to_list({ Atom }) -> [Atom].
% end.

Chapter 4, question 3

Part 1 is making a timer function.


now_to_seconds({Mega, Sec, _}) ->
    (Mega * 1000000) + Sec.

now_to_microseconds({Mega, Sec, Micro}) ->
    Micro + (now_to_seconds({Mega, Sec, Micro}) * 1000000).

dotiming({Fn, Start}) -> 
    dotiming({Fn, Fn(), Start, now()});
dotiming({Fn, Result, Start, End}) -> 
    {{ function, Fn }, 
     { result, Result }, 
     { time_microsecs, now_to_microseconds(End) - now_to_microseconds(Start)}}.

timeit(Fn) -> dotiming({Fn, now()}).

% nic.erl ends here

I struggled with this for a few hours because I couldn't see how to subtract one time from another. In the end I cheated and went and pinched a definition of now_to_seconds from a StackOverflow answer. That let me deal with the time in the way I wanted to... but maybe I missed something idiomatic?

The second part of the question asks you to build a pretty printer for the current date and time:


% Formatting the current day
%   nic:my_date_string(). -> "12th october 2014"

month(N) -> 
    element(N, {january, february,
                march, april, may, 
                june, july, august, 
                september,  october, november, 

day_ordinal(N) when N < 11, N > 13 ->
                   case (N rem 10) of
                       1 -> "st";
                       2 -> "nd";
                       3 -> "rd"
day_ordinal(N) when N >= 11, N < 14 ->
    io_lib:format("~wth", [N]).

my_date_fmt({{Year, Month, Day}, {Hour, Minute, Second}}) ->
    io:format("~w:~2..0w:~2..0w ~s ~w ~w~n", 
              [Hour, Minute, Second, day_ordinal(Day), month(Month), Year]).

my_date_string() ->

The erlang format printing is a little bit unusual I guess. That part of it involved me constanly referring to the erlang io manual.

I also experienced a little annoyance with the book at this point. I'm a very doing learner. I don't like the overly academic and this question felt unnecessarily we don't know that yet. But these days it's so easy to just Google. Often in the past I've thought of that as cheating. But now that looking up answers on the Internet is my career I don't see it the same way.

Chapter 4, question 5

Back to the trivial:

-export([even/1, odd/1, filter/2,split/1,split2/1]).

even(X) when X rem 2 == 0 ->
even(X) when X rem 2 > 0 ->

odd(X) ->

These are actually done in the chapter a little earlier so I'm not sure why he did this. I tried to write them a little differently, I did them with guards so pattern matching. Emacs could do a better job of highlighting the patterns in this situation?

Chapter 4, question 6

Again, trivial:

filter(F, L) ->
    [X || X <- L, F(X)].

The only catch was the ordering of the clauses, I think Python has the same as this, something like:

[X for X in L if F(X)]

but it still tripped me up, I tried this at first:

[X || F(X), X <- L].

I think I just expected to be writing things backwards.

Chapter 4, question 7

Again, this one wasn't hard either. I didn't really have to think about this much, it's just reiterating what was said in the chapter.

split(L) ->
       filter(fun (X) -> even(X) end, L),
       filter(fun (X) -> odd(X) end, L) 

odds_evens([H|T], Odds, Evens) when H rem 2 == 0 ->
    odds_evens(T, Odds, [H|Evens]);
odds_evens([H|T], Odds, Evens) when H rem 2 > 0 ->
    odds_evens(T, [H|Odds], Evens);
odds_evens([], Odds, Evens) ->
    { Odds, Evens }.

split2(L) ->
    odds_evens(L, [], []).

Again, I did it with guards instead of a case statement. I may try and add guard syntax highlighting to the Emacs Erlang mode, I think that would be very useful.

So how goes learning Erlang?

I haven't devoted as much time to it as I would like... and that worries me because mostly I am falling over syntax and learning syntax requires practice. For me the questions need to be spread through the book a bit more and there need to be more of them.

I have also more than once cursed Joe for not making an answers site somewhere. It would be nice to discuss Erlang in that way.

I think I need a project to do in Erlang, to have my mind on as I learn it properly so I decided I would try and write an HTTP client that can talk on Unix sockets. Curl has miserably failed to add that functionality (despite the presence of a patch) so it seems like a good thing to do.

that's all so far ...

I'll do more as I get them I guess.