【发布时间】:2012-05-13 13:39:19
【问题描述】:
我知道 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 多长时间才能感觉它们不像黑魔法? :-)
谢谢! 托德
【问题讨论】:
-
如果您不打算使用变量,可以将其名称替换为下划线:
_ <- setInput str -
我猜这是最像 Scala 的方式。
-
不确定这是否真的可行,但是通过将这些语句移动到 for 的主体,这可能看起来更自然,您可以真正采用程序风格。