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

TOB*_*TOB 20 monads haskell scala

我知道Haskell的

do
  x <- [1, 2, 3]
  y <- [7, 8, 9]
  let z = (x + y)
  return z
Run Code Online (Sandbox Code Playgroud)

可以用Scala表示为

for {
  x <- List(1, 2, 3)
  y <- List(7, 8, 9)
  z = x + y
} yield z
Run Code Online (Sandbox Code Playgroud)

但是,特别是与单子,哈斯克尔往往有内部语句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
Run Code Online (Sandbox Code Playgroud)

如您所见,它保存位置和输入,在字符串上运行解析器,然后在返回结果之前恢复输入和位置.

我不能为我的生活弄清楚如何转换setInput str,setInput oldInput以及setPosition oldPos到斯卡拉.我认为如果我只是把无意义的变量放入其中就可以使用了<-,就像我一样

for {
  oldPos <- getPosition
  oldInput <- getInput
  whyAmIHere <- setInput str
  result <- parser
  ...
} yield result
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢!托德

ehi*_*ird 26

是的,该翻译是有效的.

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!",所以你不会把它的结果绑定到变量.

(至于monad是黑魔法,你可以拥有的最好的实现是它们并不是真的很复杂;试图在它们中找到更深层的含义通常不是一种学习它们如何工作的有效方式.它们只是一个界面编写碰巧特别常见的计算.我建议阅读Typeclassopedia来掌握Haskell的抽象类型类,尽管你需要阅读一般的Haskell介绍才能从中获得更多.)

  • Monad的答案非常好.这只是一种编程模式.没有什么"黑魔法". (2认同)
  • 根据For-comprehension对于scala执行`>>`的糖实际上只是为`{_ < - M}做` (2认同)