I tried to learn Haskell about a year ago. Which was basically ordering a book (“Programming in Haskell” by Graham Hutton) via the training budget of my employer, to rage quit after reading about 100 pages. It was probably not the book, but I wasn’t really focused, so I moved on to other things.
Since then I have returned to Go, and wrote a non trivial amount of code, and it was alright. At some point I stopped thinking about the language and wrote code fluently, and that’s a good thing, even if I found Go itself a bit boring.
So in my search of adding a new exciting language to my toolset, I was reading a bit about Scheme –again, I know–, and long story short I decided to go back to Haskell. I’m reading now Learn You a Haskell for Great Good!, that has the advantage of having a free version that can be read online, and it is more direct that the other book I have. And I’m enjoying it!
I’m still on chapter 5 (of 14), so it is a bit early, but so far I’m finding it very similar to Scala –with the Typelevel stack, see Cats and Cats Effect–, and you can tell that Haskell has been a great influence –assuming it is not the other way around because in some cases, Scala seems to get the features a bit further–.
Reading technical books is hard because, at least for me, it feels like it is a lot of information that I don’t seem to retain, until I need to apply that information and then it surfaces –most of the time at least–. So now that it felt like I knew some Haskell, and following the Scala similarities, I wrote a small command line tool: Tomato.
It is a very simple Pomodoro tool –in reality is just a timer–, that is inspired by pomo in Go by Rob Muhlestein. I think I saw it in one of his streams and I thought it was neat. It is a simple tool, but it has already some meat to it, including input/output, which is perfect to practice some of the tricky bits from Haskell.
And the experience was very nice. Most of my problems were with some syntax I don’t know yet, and specially with a couple of libraries I had to use. They are documented, but perhaps I missed some examples.
For example, I spent way too much time to figure out how to add minutes to an UTC time.
Let’s look at this function:
doStart :: String -> Integer -> IO () doStart stateFile mins = do currTime <- getCurrentTime let deadline = addUTCTime secs currTime writeFile stateFile (show deadline) putStrLn ("Started, end on " ++ show deadline) where secs = secondsToNominalDiffTime (60 * fromInteger mins)
It creates the state file with the UTC time adding the deadline for the timer, I had initially the minutes as an
Int –and not an
Integer; the difference is subtle– and
secondsToNominalDiffTime requires a
Pico type to produce the
NominalDiffTime instance required by
addUTCTime. Sometimes you can have this same problem in Scala, which I call type-matching bingo. The solution is clean, but oh it wasn’t easy to get there!
The library to deal with the program arguments gave some trouble as well, even considering the docs has two good examples. But in that case, it was only me to blame, and when the function signature clicked, then I understood how the defaults for the options worked. It was all because for the state file I’m using
XDG_CACHE_HOME, and the function to get that directory returns an
IO, so I couldn’t use exactly any of the examples.
The similarities with Scala are definitely a good thing:
Either is the same, pattern matching is very similar –although Scala seems more flexible; it could be me not knowing all the tricks in Haskell though–, the
IO Monad in Cats Effect is modelled after Haskell’s
The LSP support via haskell-language-server is good, although I tried to do a rename and it wasn’t supported. The docs are good, and I specially like that on hover you see the docs and a link to a local HTML file with the full docs of that package.
Perhaps the discoverability of Haskell is worse than in Scala, because of the syntax. In Scala you have a value and you can inspect methods with the help of your editor and LSP by just using
value., but in Haskell syntax it seems to me like all are functions, so the dot trick is not possible. So at the end it is a bit overwhelming having all that API, but not really knowing it, so good look finding
secondsToNominalDiffTime to start with!
You can see that the book intro to lists includes a lot of functions that you probably need to learn, eventually, and this is also a bit of a problem with Scala. You are trying to solve a problem, and the cleanest and most elegant solution is on a method you don’t know about.
All these are just first impressions, and I’m sure that I wrote some code that is a bit over my current knowledge of the language, but it wasn’t too frustrating and it only took me a bit longer that it should have. I found myself thinking about Scala native, because of those bits that feel a bit less flexible in Haskell than in Scala, but I have to say that I’m interested and I’ll keep going!