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.
Unfamiliar operators
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 .
or >>>
from 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):
Flow | Base |
---|---|
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.
1 | Haskell> -- Composition and the inverted flow <--- |
1 | Haskell> -- Piping in unnatural direction <--- |
What happened to flatten?
Until I tried Python, started developing in JavaScript and toyed with Haskell I really didn’t know how great the Scala’s collection API actually is.
Scala utilizes so called fluent interface in its collections API. I very like how concise it is.
1 | 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], [[4]]]
it creates [1, 2, 3, [4]]
. 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.
1 | 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 map
+ flatten
with flatMap
. Let’s do it.
1 | scala> (1 to 10).map(_ * 5).filter(_ > 25).flatMap(x => List(x, x + 3)).sorted |
I will show how solutions in JavaScript and Python looks like. JavaScript version uses Lodash library. I am actually not sure if JavaScript contains all functions necessary for this example if one would desire to rewrite it to Vanilla JavaScript (are there functions like range
or flatMap
?).
1 | > _ = 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.
Alright, JavaScript version is not amazing - has some repetition and is not as concise as Scala or Haskell, but overall quite good.
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.
1 | 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 flatMap
.
1 | Haskell> sort . (>>= (\x -> [x, x + 3])) . filter (> 25) . map (* 5) $ [1..10] |
For comparison I will rewrite it to be more Scalish and Flowish.
1 | 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.