I’m going through Get Programming with Haskell by W. Kurt. (Sorry, not an open-source book.) and I find chapter 10 a hard nut to crack. It talks about “how to build OOP [object-oriented programming] by using closures, lambdas, and first-class functions”.
This is certainly a beginner’s question. To describe better what’s troubling me here I show the “OO” structure set up in the book, a system for cups of liquid and the volumes of these cups. (I adapt the code to the metric system, so that I don’t copy the book’s code too bluntly.)
First we define a “constructor” helper function for cup “objects”. These objects contain exactly one property, the cup size in millilitres:
cup ml = \msg -> msg ml
Then we “instantiate” a specific cup:
mediumCup = cup 250
And finally we define a “getter” helper function to read out the size of a specify cup:
getSize aCup = aCup (\ml -> ml)
When I now type in the expression
getSize mediumCup
I get in GHCi to my amazement the size of the cup back:
Main> 250
It dawns upon me that the magic happens because the “objects” are functions themselves! But then I look at the inferred types of the helper functions. HLS tells me:
cup :: t1 -> (t1 -> t2) -> t2
cup ml = \msg -> msg ml
mediumCup :: (Integer -> t2) -> t2
mediumCup = cup 250
getSize :: ((p -> p) -> t) -> t
getSize aCup = aCup (\ml -> ml)
Here I am surprised that getSize
has the type ((p -> p) -> t)
and not ((p -> t) -> t)
. Because,if I understand it correctly, the argument aCup
is of the type of mediumCup
. i.e. a function (Integer -> t2) -> t2
.
And this is only the beginning of what’s clouding my head. The whole structure is pretty mind blowing. Is it worth it to get to the bottom of this “OO” chapter?