Here’s a question that came up while I’ve been trying to
href="http://greenokapi.net/blog/2009/05/04/currying-in-perl/">implement
currying in Perl: is Currying monadic?
I’ve tried a couple of times, but not managed to explain what I mean very well on #haskell, so let’s
see if a longer writeup explains it better.
My simplistic understanding of monads is that they take various things that
are nests of nested expressions, and allow you to reason about them, and
given them a pretty syntax that makes it look like they are in fact a
sequence of commands.
For example: (pseudocode)
let a = 1
let b = 2
output a+b
Looks like a sequence of commands, but you couldn’t just separate each
line and string the commands together. Rather you have to consider it
as a nest:
(let a = 1
(let b = 2
(output a+b )))
And in many cases, we can go from a nested structure to a monad, for example, we could simplify these horribly nested ifs:
(if file exists
(if file is readable
(if reading the file gave a string
(if the string matches a username
(do some action with the username)))))
… into a nice Maybe monad:
do check file exists
check file is readable
string <- read from file
check string matches username
do something with the username
Similarly, nested lists:
(for each i in list 1
(for each j in list 2
(is i the same as j?
(output i))))
can be abstracted as a List monad:
do i <- list 1
j <- list 2
check i == j
output i
OK, so I'm not talking about wrapping and unwrapping values, the monad
laws, or typing in general. They are what gives this stuff its strong
theoretical basis and makes it robust. But the simple-minded "Nest ->
Sequence" idea works for me at least, and gives a good feel for
where monads can come in useful.
Currying
So... when I was implementing currying, I noted that you could write a
currying sub (pseudocode again):
function add3 (a, b, c) {
return a+b+c
}
as something like this:
function add3 (a) {
return function (b) {
return function (c) {
return a+b+c
}
}
}
This is again a nested expression. So I wondered if you could again "flatten" it with a monadic do block:
let add3 = do
a <- get first parameter
b <- get second parameter
c <- get third parameter
return a+b+c
OK, so I "know" that functions in Haskell (which uses currying for
functions as a general rule) are the "Reader monad". But I don't
understand it well enough to know if that means you can use Reader to
implement the above...
(I don't understand Reader at all in fact. I must bang my head against
it again, but I find it very confusing - how the monad is represented,
what the functions are, and how they get magically applied.)
So, I did attempt to implement it using my Perl module
Acme::Monads. This
href="http://github.com/osfameron/acme--monads/blob/master/t/04_curry.t">test
shows that this sort of works:
my $add = mdo (2) {
mbind $x = Curry shift;
mbind $y = Curry shift;
return $x+$y;
};
say $add->(1)->(2); # 3, yay!
Note that the "return" isn't a monadic Unit but Perl's return,
i.e. a plain value. That makes this example strictly speaking not
monadic: what I don't know is whether that means the whole idea is fatally flawed, or whether (as I believe) I was just too dumb to fix the errors I got when I tried running with munit...
I suspect that it should be possible, with the
whole expression then being wrapped by some function
(runCurry?) which extracts the final result out of the monad.
Did this explanation make any sense? Please let me know, and any
comments on whether it's possible/sane to do this (writing currying as a
monad) are appreciated!