I know that Haskell's
do
x <- [1, 2, 3]
y <- [7, 8, 9]
let z = (x + y)
return z
can be expressed in Scala as
for {
x <- List(1, 2, 3)
y <- List(7, 8, 9)
z = x + y
} yield z
But, especially with monads, Haskell often has statements inside the do
block that don't correspond to either <-
or =
. For example, here's some code from Pandoc that uses Parsec to parse something from a string.
-- | Parse contents of 'str' using 'parser' and return result.
parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a
parseFromString parser str = do
oldPos <- getPosition
oldInput <- getInput
setInput str
result <- parser
setInput oldInput
setPosition oldPos
return result
As you can see, it saves the position and input, runs the parser on the string, and then restores the input and position before returning the result.
I can't for the life of me figure out how to translate setInput str
, setInput oldInput
, and setPosition oldPos
into Scala. I think it would work if I just put nonsense variables in so I could use <-
, like
for {
oldPos <- getPosition
oldInput <- getInput
whyAmIHere <- setInput str
result <- parser
...
} yield result
but I'm not sure that's the case and, if it is correct, I'm sure that there must be a better way to do this.
Oh, and if you can answer this question, can you answer one more: how long do I have to stare at Monads before they don't feel like black magic? :-)
Thanks! Todd
Yes, that translation is valid.
do { x <- m; n }
is equivalent to m >>= \x -> n
, and do { m; n }
is equivalent to m >> n
. Since m >> n
is defined as m >>= \_ -> n
(where _
means "don't bind this value to anything"), that is indeed a valid translation; do { m; n }
is the same as do { _ <- m; n }
, or do { unusedVariable <- m; n }
.
A statement without a variable binding in a do
block simply disregards the result, usually because there's no meaningful result to speak of. For instance, there's nothing interesting to do with the result of putStrLn "Hello, world!"
, so you wouldn't bind its result to a variable.
(As for monads being black magic, the best realisation you can have is that they're not really complicated at all; trying to find deeper meaning in them is not generally a productive way of learning how they work. They're simply an interface to compose computations that happen to be particularly common. I recommend reading the Typeclassopedia to get a solid grasp on Haskell's abstract typeclasses, though you'll need to have read a general Haskell introduction to get much out of it.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With