我知道Haskell的
do
x <- [1, 2, 3]
y <- [7, 8, 9]
let z = (x + y)
return z
可以用Scala表示为
for {
x <- List(1, 2, 3)
y <- List(7, 8, 9)
z = x + y
} yield z
但是,特别是对于monad,Haskell通常在do
块中包含与<-
或=
不对应的语句。例如,这里有一些来自Pandoc的代码,它使用Parsec来解析字符串中的某些内容。
-- | 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
如您所见,它保存位置和输入,在字符串上运行解析器,然后在返回结果之前恢复输入和位置。
我无法终身了解如何将setInput str
,setInput oldInput
和setPosition oldPos
翻译成Scala。我认为如果我只是放入无意义的变量就可以了,所以我可以使用<-
,比如
for {
oldPos <- getPosition
oldInput <- getInput
whyAmIHere <- setInput str
result <- parser
...
} yield result
但我不确定是不是这样,如果它是正确的,我确信必须有更好的方法来做到这一点。
哦,如果你能回答这个问题,你能再回答一下:在他们感觉不到黑魔法之前,我要多久盯着Monads? : - )
谢谢! 托德
答案 0 :(得分:25)
是的,该翻译有效。
do { x <- m; n }
相当于m >>= \x -> n
,而do { m; n }
相当于m >> n
。由于m >> n
被定义为m >>= \_ -> n
(其中_
表示“不将此值绑定到任何内容”),这确实是有效的翻译; do { m; n }
与do { _ <- m; n }
或do { unusedVariable <- m; n }
相同。
do
块中没有变量绑定的语句只是忽略了结果,通常是因为没有有意义的结果可言。例如,putStrLn "Hello, world!"
的结果没什么好处,所以你不会把它的结果绑定到变量。
(至于monads是黑魔法,你可以拥有的最好的实现是它们并不是真的很复杂;试图在它们中找到更深层的含义通常不是一种有效的方式来学习它们如何工作。它们是只是一个组合计算的接口,这个接口恰好是特别常见的。我建议阅读Typeclassopedia以掌握Haskell的抽象类型类,尽管你需要阅读一般的Haskell介绍才能从中获取更多信息。 。)