This section of Seven Languages and Seven Weeks focused on control structures, primarily pattern matching and higher-order functions primarily in the form of list manipulation and anonymous functions.
The response to question one show some basic list processing in Erlang. The get function uses erlang's built-in lists:filter function to get tuples where the keyword matches what the caller passed in. The nice part is the destructuring assignment on the right that lets one quickly extract what we want to return, namely the value. In an Erlang pattern match, we can replace parts we do not care about with an underscore '_', I have done this here for the rest of the list returned from filter. I was only interested in the first match. I could have done the same for MatchKey (and Erlang even warns you that it is unused in the function) but left it in the first function for extra clarity. We then return MatchVal.
Note that if the keyword is a key in one of the tuples in a list, this function will fail (it will throw an error). This is because result of filter namely '[]', the empty list, does not match the left hand side of the equal sign, the two cannot be unified. If you want to return some default value, like nil for example, the next two functions provide this. getOrElse takes a value to return if the keyword is not found. To achieve this we take the result of the initial filter, and do a more flexible pattern match using the case syntax of Erlang. This form lets us match the variable Ans to any pattern we are interested in (and we can still do destructuring while we are at it!). When Ans is the empty list we return the default value the caller gave us, else we destructure and return the value associated with that keyword. Note the use of _ for parts of the match we don't need to get our answer.
I really like this combination of pattern matching and destructuring that lets one very easily describe the structure you want to create or retrieve.
We continue to use this way of describing structure in combination with a powerful syntax for list comprehensions in Erlang. List comprehensions allow one to quickly build a list by iterating (and filtering) over a list. The last line of the function q2() is the list comprehension. The basic format is
[ Expression || Clause1, Clause2, ... ]
In this example Clause1 is {Item, Quantity, Price} <- List. This clause is a generator, it produces the structure on the left of the arrow for every element of the List on the right. In this case we just happened to destructure it into a tuple with variables we want to use as well. We do not have any other clauses, but in addition to the ability to have multiple generators in a list comprehension, you can also add filters that filter the elements coming out of the generator. It is a really neat syntax, the erlang docs have some really understandable examples showing some of the things list comprehensions can be used for, including an implementation of quicksort.
q2pencil() was just a reminder of how pattern matching in a destructuing assignment can also be used to filter results. This form of the q2 function will only match pencils since we explicitly put the pencil atom (lower case identifiers are not variables but atoms in erlang, similar to prolog atoms), in the function. It only matches with pencil. Like i said, I really like the pattern matching/destructuring :-).
The final exercise immediately think of the magic square code I had written in prolog! My answer really shows Erlang's Prolog heritage, since I copy-pasted a bunch of it over :-). I was able to make it a bit shorter than i probably would have been able to in prolog though.
We first destructure the board and get it into rows, columns and diagonals. Then we check if there is a winner (note case is an expression i.e. it returns a value). We use a pattern match to check if a winner was detected else we check if there is still space to play or we declare a tie. It is really quite concise, and I really like the conciseness of the pattern match on same(Line) that lets us quickly determine who won, it just looks cleaner than the traditional if statement I would use. Have i told you about the pattern matching :-).
Though all kidding aside, pattern matching seems pretty fundamental to idiomatic Erlang (though i cannot claim my code is idiomatic). The only tricky part in writing this function was dealing with the fact that as far as i can tell, Erlang has no way to return early from a function (though I know many people in other languages eschew multiple return points in a function). I initially wanted to return from the function early if a winner was detected, else it checked the other rows and could print that there was no winner as well. The reason for the second pattern match (on Winners) is because I couldn't do this. The result is pretty clean though, so I am not complaining too much. It forces you to be more explicit about flow through the function. That could be mildly annoying in certain situations though.
In any case day 2 of Erlang was fun. Full code is on github.