I don’t earn by writing Scala, but I did quite a fair of Scala when working on my Minecraft mod and my master’s thesis. I am very interested in functional approaches, so for a long time I wanted to learn Haskell. I bought a book “Learn You a Haskell for Great Good” and started reading and testing examples. In this short article I point out some things I found to be odd or not that good as in other languages I encountered. Don’t read this as a bashing of Haskell, I love the language (the type inference is so strong), but no language (not even my favourite Scala) is without faults and imperfections.
I already knew some basics from school. But I find some things a bit strange - things like function composition
. - why it has a reversed flow of an execution? Why aren’t more used packages like Flow with its right functional composition
.> which clearly states direction and is in my opinion more intuitive (same flow direction as in reading text and guiding character
>) and instead one should use
Control.Arrow when writing The Only Right Haskell™.
I love pipe operator (forward function application) from ScalaZ -
|>. I was mildly disappointed that Haskell needs an import before one can start using it and also the fact that
& isn’t as readable as
|>. I know Haskellers hate the Flow package, but I love its simplicity and consistency. If you are not a Haskeller, just look at the table (if you are, you probably already dislike the Flow library):
|x |> f||x & f|
|f <| x||f $ x|
|apply x f||f x|
|f .> g||f >>> g|
|g <. f||g . f|
|compose f g x||g (f x)|
|x !> f||-|
|f <! x||f $! x|
|apply’ x f||seq x (f x)|
I just really like how the pipes (applications) and compositions look. If you can’t picture it have a few examples.
Haskell> -- Composition and the inverted flow <---
Haskell> -- Piping in unnatural direction <---
Scala utilizes so called fluent interface in its collections API. I very like how concise it is.
scala> (1 to 10).map(_ * 5).filter(_ > 25).map(x => List(x, x + 3)).flatten.sorted
Now the shock - Haskell doesn’t have
flatten function? The flatten takes a list of lists and makes it one level more flat - e.g. from
[1, [2, 3], []] it creates
[1, 2, 3, ]. I found some intricate solutions on StackOverflow, but it turns out the function I was looking for is named
concat. If you ask me it is not a best name. Let us see the Scala example turned into idiomatic Haskell.
Haskell> import Data.List
I still dislike the inverted flow of execution/reading, but to my best knowledge this is the recommended way. Also note that I am required to import a package to actually do the sorting, a bit unexpected (Scala runs fine without any import whatsoever).
Those with some FP experience probably already spotted a possible improvement - using Scala one can replace
flatMap. Let’s do it.
scala> (1 to 10).map(_ * 5).filter(_ > 25).flatMap(x => List(x, x + 3)).sorted
> _ = require('lodash');
I have to note that FP version of Lodash might look a bit better, but I don’t think it would be much more concise - I don’t see a way how to shorten those lambdas.
Let’s do the Python version. Oh, Python entirely lacks
flatMap, you have to define it on your own. Just from this fact one can quite safely deduce that Python is very weak in the FP land. I am no Python guru, just occasional (usually involuntary) user.
from itertools import chain
What a mess… Even if there is some wonderful Python FP library the loong lambda notation is just awful.
What about Haskell? Well, it took me some time to stumble upon operator
>>=. Is it just me, or names in Haskell are not that great? By the way it is called bind and according to StackOverflow it is a bit weaker than Scala’s
Haskell> sort . (>>= (\x -> [x, x + 3])) . filter (> 25) . map (* 5) $ [1..10]
For comparison I will rewrite it to be more Scalish and Flowish.
Haskell> let flatMap = flip (>>=)
It is a bit longer than the idiomatic version, but I like it way more - it just has a nice flow.