21

我知道 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块内有不对应于<-or的语句=。例如,下面是 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 oldInputScala setPosition oldPos。我认为如果我只是把无意义的变量放进去,这样我就可以使用了<-,比如

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

但我不确定情况是否如此,如果它是正确的,我相信一定有更好的方法来做到这一点。

哦,如果你能回答这个问题,你能再回答一个吗:我必须盯着 Monads 多长时间才能感觉它们不像黑魔法?:-)

谢谢!托德

4

1 回答 1

28

是的,那个翻译是有效的。

do { x <- m; n }等价于m >>= \x -> ndo { m; n }等价于m >> n。由于m >> n被定义为m >>= \_ -> n(其中的_意思是“不要将此值绑定到任何东西”),这确实是一个有效的翻译;与或do { m; n }相同。do { _ <- m; n }do { unusedVariable <- m; n }

块中没有变量绑定的语句do只会忽略结果,通常是因为没有有意义的结果可言。例如, 的结果没有什么有趣的事情putStrLn "Hello, world!",因此您不会将其结果绑定到变量。

(至于 monad 是黑魔法,你能得到的最好的认识是它们一点也不复杂;试图在它们中找到更深层次的含义通常不是学习它们如何工作的有效方式。它们只是一个接口编写碰巧特别常见的计算。我建议阅读Typeclassopedia以牢固掌握 Haskell 的抽象类型类,尽管您需要阅读一般的 Haskell 介绍才能从中学到很多东西。)

于 2012-05-04T01:45:28.433 回答