Scala相当于Haskell的记号(再次)

时间:2012-05-04 01:33:49

标签: scala haskell monads

我知道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 strsetInput oldInputsetPosition oldPos翻译成Scala。我认为如果我只是放入无意义的变量就可以了,所以我可以使用<-,比如

for {
  oldPos <- getPosition
  oldInput <- getInput
  whyAmIHere <- setInput str
  result <- parser
  ...
} yield result

但我不确定是不是这样,如果它是正确的,我确信必须有更好的方法来做到这一点。

哦,如果你能回答这个问题,你能再回答一下:在他们感觉不到黑魔法之前,我要多久盯着Monads? : - )

谢谢! 托德

1 个答案:

答案 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介绍才能从中获取更多信息。 。)