Learning Us a Haskell for Great Learnings

haskell

I recently reconnected with a friend from high school, Vrushank Vora. Vrushank had been trying to teach himself Haskell, and suggested that we collaborate on teaching ourselves Haskell over the next few months.

I thought this was a great idea. I’ve tried Haskell before, but have never really gotten deep into it. I’m not quite sure why this is - I’ve written plenty of functional-style code in Ruby and Clojure - but perhaps being forced to write in a functional style stymied me more than I’d like to admit. It is, after all, very easy to fall back into an imperative style, if there’s nothing preventing you from doing so.

Here’s the quick notes of what we did, and what we learned. To prepare, we read chapters 2 through 5 of Learn you a Haskell for Great Good. Without much of a formal plan, we decided to try some exercises from Code Wars. We ended up only being able to complete the screener that Vrushank needed to do to sign up and one other exercise.

First discovery: you access the fields of a record-syntax defined type with functions that corresponds to the field names. That is, if you have data Person = { name: String } as your type, and a Person that you have bound to, say, person, you would access the name of the person with name person. This was a little counter-intuitive to me coming from an Object Oriented / Message Passing background, but is really quite a clean way to do it.

We then did an exercise on writing a function to determine if a string is an “Isogram”, that is, if all the letters in the string are unique. This one took us a little longer.

I will say that the red-green-refactor strategy worked wonderfully for us. Our first version of the function was something to the effect of:

1
2
3
4
5
isIsogram :: String -> Bool
isIsogram xs = if null xs
                 True
               else
                 not ( (head xs) `elem` (tail xs) ) && isIsogram ( tail xs )

But, we ended up refactoring the code to be fairly beautiful, something to the effect of:

1
2
3
4
5
6
caps :: String -> String
caps = map toUpper

isIsogram :: String -> Bool
isIsogram "" = True
isIsogram (x:xs) = (toUpper x) `notElem` (caps xs) && isIsogram xs

There was an alternative solution that did not define a caps function. One of the questions I have is - which would be “better” Haskell? Is it better to define lots of named functions, or fewer?


I'm looking for better ways to build software businesses. Find out if I find something.