Programming Erlang Book Club

I’ve been thinking something similar Rainer. When we came to the first exercise I felt being a bit more specific would have helped avoid some head-scratching because I wasn’t 100% sure what was required of me (something like “do this and this which should result in this” would have helped avoid any doubt, for me at least).

I am also beginning to wonder whether the book had a different target audience in mind to perhaps who the majority of its readers might actually be?

For instance the bit about division. I will be the first to admit that I have forgotten most of what I learned in school :see_no_evil: even though Maths was actually my strongest subject and I was often top of the class, now, I am lost without a calculator! :man_facepalming: Although what’s in the book is technically correct 5 rem 3. > 2 the example might have been better explained with 7 rem 2. > 1 (7 divided by 2 equals 3 with a remainder of 1). I know it’s just a small thing but this example and an additional sentence could have helped explain it fully avoiding the need to search for a recap (again, for me and others like me who need that recap). Not sure if anyone else would agree mind - maybe everyone else reading it is little bit more academic than me :laughing:

At the time I read your post I was actually re-reading the bit on funs, and I wondered, what led to the decision to use What and X for the variable names given we’re talking about items and quantities:

total([{What, N}|T]) -> shop:cost(What * N + total(T));

Again, for those who need things spelling out for them (like me!) maybe this would make things a little easier?

total([{Item, Qty}|T]) -> shop:cost(Item * Qty + total(T));

Or even:

total([{Item, Qty}|Tail]) -> shop:cost(Item * Qty + total(Tail));

I know it seems like a tiny detail, but it just made me wonder, are the examples in the book intended to look familiar to people with a mathematics background? Were they the intended target? Or was it just Joe’s way of wanting us to think more in those terms …or just the way he happens to think himself?

Still none of this is detracting from how much I love the book :nerd_face:

1 Like

Sometimes I had the same feeling :wink:
I thought that’s just a thing that functional programmers do differently (more math-like) than oop programmers (which I am in my job). But just needed to read it twice and then I was ok with it.

I did the second exercise of chapter 5 now, 2 different versions:

5.2 with recursion
map_search_pred(Map, Pred) ->
    list_search_pred(maps:to_list(Map), Pred).

list_search_pred([], _) -> {};
list_search_pred([{K, V}|T], Pred) ->
    case Pred(K, V) of
        true -> {K, V};
        false -> list_search_pred(T, Pred)
    end.
5.2 with list comprehension
map_search_pred2(Map, Pred) ->
    [H|_] = [{K, V} || {K, V} <- maps:to_list(Map), Pred(K, V)],
    H.

Maybe we shouldn’t use the second version as it will performe bad I guess, but I like it for the small amount of code needed :smiley:

2 Likes

I’m up to List Comprehensions so still quite a while behind you. I wanted to re-read part of the chapter but hopefully I’ll be able to catch up a bit tonight. Nice to see you are still flying thro it :stuck_out_tongue: :laughing:

1 Like

Another maths orientated thing I spotted (and what left me scratching my head) is on page 54, where we encounter lists:filter(P,L) “which returns a new list of all the elements E in L such that P(E) is true”.

E is easy enough to figure out (elements) as is L (list) but what’s P stand for? Felt like I was missing something :man_shrugging:

On the quicksort example (which is as far as I’ve got atm) I was hoping to be walked through each step of the recursion too, just for that extra bit of reinforcement and clarification of what is going on exactly.

This did get me wondering whether it might be worth reading another Erlang book alongside this book - what’s better than someone teaching you something? Two people teaching you the same thing! :laughing:

I find getting two different perspectives on something can help, hence wondering what you think of reading this alongside Learn You Some Erlang for Great Good! (No Starch Press) (Paid/Free)


Edit:

From the top of this post:

On page 60, it’s explained:

Filters are either predicates (functions that return true or false) or boolean expressions

I don’t think I’ve heard functions that return true or false being described as predicates before, at least not explicitly like this. (Would have been cool if this was mentioned nearer page 54 :upside_down_face: :laughing:)

1 Like

In exercise 5 ‘Pred’ is also used, i just noticed it then :smiley:

I agree it would be good to read a second book parallel to deepen the knowledge, just I fear then we’ll never end :stuck_out_tongue:

I was busy renovating a room for my new home office, so no progress today…

1 Like

Least I know what it means now :sweat_smile:

I usually find books are split into separate parts, which helps make it easy to match similar books together. So we could start Learn You Some Erlang for Great Good! (No Starch Press) (Paid/Free) at the end of part 2? (So after chapter 10)… or we can see how it goes for now? If things start getting hairy we could always start it sooner or if we find it’s not needed, hold off :nerd_face:

That’s good to hear Rainer! It’ll give me chance to catch up :rofl:

Post pics when it’s all done! :+1:

1 Like

3 posts were split to a new topic: Which of the Visual Studio Code extensions do you use for Erlang development?

I’ll proceed with only reading this book at the moment, as long as I don’t get into bigger troubles :wink:
I shouldn’t start more things, already have too many spawned processes :smiley:

Finished reading chapter 6, nothing exceptional here (ok, bad joke, it’s about exceptions).
Error handling isn’t the most exciting topic for me, but I like Erlangs ‘fail fast’ & ‘let it crash’ strategy.

Do we have a homeoffice thread? Or so far just the standing desk thread?

2 Likes

Haha, cool, I’ll stick with it too for now then - tho I haven’t had much time for it. Hope to catch up soon tho! Wel done on getting through chapter 6!!

There’s this one :nerd_face:

1 Like

Whoo hoo welcome to the club DG :nerd_face: I am sure you will catch up to me pretty soon as this time of year is always hectic for me.

Unfortunately I haven’t had much time to get further into the book (sorry @Rainer!) but I keep meaning to post a thread about visualising recursions - I’ll try to do that soon and mention it in this thread :smiley: How you getting on @Rainer - bet you’re way ahead now :laughing:

2 Likes

This week was very busy at work, so no big progress :wink:
Just this:

Exercise 6.1

-module(ex6).
-export([read1/1, read2/1]).

read1(File) ->
{ok, Bin} = file:read_file(File),
Bin.

read2(File) ->
case file:read_file(File) of
{ok, Bin} -> Bin;
{error, Why} -> throw({filenotfound, Why})
end.

I did 2 different versions, in the first one I just let pattern matching throw the exception, in the second I did it myself.

2 Likes

No complaints here - it gives me and @DevotionGeo a chance to catch up :laughing:

Glad you are managing to get through the challenges tho :+1:

2 Likes

Thank you Aston!
I can spare only a small chunk of time to this book so you and @Rainer will be ahead of me, but I shall try to catch up.

3 Likes

Welcome to our club @DevotionGeo :slight_smile:

I skipped exercise 6.2 as it’s not so interesting for me at the moment, and continued reading.
I’m now in middle of chapter 7, and it’s exciting :smiley:
It’s about binaries and how we can pattern match on single bits, that’s cool stuff. Especially if I think how I’d do it in C++ and what amount of awkward code I’d produce…

On a side note: In one example the notation 16#12345678 is used, which I seem to have missed (or already forgotten again) in chapter 3. It means this is Base16 notation, which is HEX. Another example: 2#11 is binary and evaluates to the integer 3.

3 Likes

Thank you @Rainer! :slight_smile:

2 Likes

The exercises for chapter 7 are quite tricky, but finally I finished them :smiley:

Exercise 7
-module(ex7).
-export([reverse_binary/1,term_to_packet/1, packet_to_term/1, test/0, reverse_bits/1]).

% 7.1
reverse_binary(Binary) ->
    reverse_binary(Binary, <<>>).

reverse_binary(<<>>, Binary) ->
    Binary;
reverse_binary(<<Head, Tail/binary>>, Accumulator) ->
    reverse_binary(Tail, <<Head, Accumulator/binary>>).

% 7.2
term_to_packet(Term) ->
    Binary = term_to_binary(Term),
    N = byte_size(Binary),
    <<N:4/unit:8, Binary:N/binary>>.

% 7.3
packet_to_term(Packet) ->
    <<N:4/unit:8, Binary:N/binary>> = Packet,
    binary_to_term(Binary).

% 7.4
test() -> 
    P = term_to_packet("DevTalk"),
    "DevTalk" = packet_to_term(P).

% 7.5
reverse_bits(Binary) ->
    Bitlist = [ X || <<X:1>> <= Binary],
    Reversedlist = lists:reverse(Bitlist),
    << <<X:1>> || X <- Reversedlist >>.   

especially 7.2 took me a while…

2 Likes

I’ve read chapter 8, or better skimmed, as Joe recommended :wink:
Most interesting thing for me: Dynamic code loading. A very nice thing in Erlang :slight_smile:

Also I started the exercises, but not yet finished:

Exercise 8.1
count_dict_exports() ->
    Modinfo = dict:module_info(),
    {_, Exports} = lists:keyfind(exports, 1, Modinfo),
    length(Exports).
Exercise 8.2
count_exports(Mod) ->
    {_, Exports} = lists:keyfind(exports, 1, Mod:module_info()),
    length(Exports).

module_fn_count() ->
    List = code:all_loaded(),
    Touples = [{Module, count_exports(Module)} || {Module, _} <- List],
    Touples.

max_exports({Mod, Count}, []) -> {Mod, Count};
max_exports({Mod, Count}, [{_, C} | T]) when Count > C-> max_exports({Mod, Count}, T);
max_exports({_, Count}, [{M, C} | T]) when Count =< C-> max_exports({M, C}, T).

run()->
    max_exports({init, 0}, module_fn_count()).

Still thinking how I should solve the next Exercise :smiley:
Hope you’ll catch up soon, it’ll be very interesting to compare our solutions.

2 Likes

I’m so sorry for not being able to read anymore Rainer! This time of year is always a bit hectic for me, hopefully I’ll be able to get back to it soon :smiley: Hopefully it’s given some time for @DevotionGeo to catch up as well :nerd_face:

What do you think of the book so far? Dynamic code loading - I can’t wait to get to that!

1 Like

My time is also very limited at the moment, but usually I’m reading a bit just before sleeping :wink:
I like the book, but the more I progress the more annoyed I get by C# (my daily business) :stuck_out_tongue: I’m liking the Erlang syntax, which came unexpected :slight_smile:

I continued with the exercises, so here’s the second (of three) part from 8.2:

Exercise 8.2 part 2 (most common function name)
-module(ex8).
-export(most_common_funname/0]).

all_functions() ->
    Exports = [lists:keyfind(exports, 1, Module:module_info()) || {Module, _} <- code:all_loaded()],
    Functions = lists:flatten([Funlist || {exports, Funlist} <- Exports]),
    Functions.

get_function_counts([{Funname, _} | T])->
    case get(Funname) of
        undefined -> put(Funname, 1);
        X -> put(Funname, X + 1)
    end,
    get_function_counts(T);
get_function_counts([]) -> get().

most_common_funname() ->
    [{Funname, _} | _] = lists:sort(fun({_, A}, {_, B}) -> A > B end, get_function_counts(all_functions())),
    Funname.

I really wonder how someone experienced wold solve this. I used the process dictionary that was introduced in chapter 8 as a mutable data structure, but I think this can’t be considered ‘good practice’…

2 Likes

Thanks to all the encouraging comments in this thread, I ordered the book. It arrives on Saturday! I’ll join y’all then!

3 Likes