为什么在不需要 getLine 值时对其进行评估

  • 本文关键字:评估 不需要 getLine haskell
  • 更新时间 :
  • 英文 :


如果Haskell懒惰,为什么在以下两种情况下都会评估getLine?由于懒惰,我希望在fa的情况下不会评估getLine,因为它的结果随后不会被使用:

let fa = do {
  x <- getLine;
  return "hello"
}
let fb = do {
  x <- getLine;
  return $ x
}

(我在GHCi中测试了这两种情况)

谢谢

它的结果被使用,只是没有按照你必然期望的方式使用。 这种脱糖

fa = getLine >>= (x -> return "hello")

所以getLine的结果仍然传递给函数x -> return "hello"。 Monads 本质上是关于一起排序动作(除其他外);即使以后不使用结果,该排序仍然会发生。 如果不是这样,那么

main = do
    print "Hello"
    print "World"

不会作为程序做任何事情,因为对print的两个调用的结果都没有被使用。

恭喜你,你刚刚发现了为什么Haskell是一种纯粹的函数式语言!

结果getLine 不是字符串。这是一个碰巧"产生"字符串的 IO 操作。该字符串确实没有被评估,但动作本身是(因为它出现在绑定到 maindo块中),就副作用

而言,这就是最重要的。

真的只是getLine的价值。这不是一个函数,所以它实际上没有结果。

现在要小心... ;-)

getLine的结果不是字符串,而是"I/O 命令对象"(如果您愿意的话)。代码实际上脱糖为

getLine >>= ( x -> return "hello")

>>=运算符从现有 I/O 命令对象和函数中构造一个新的 I/O 命令对象...好吧,这有点让你思考。重要的是,I/O 操作被执行(因为实现了 >>= for IO),但其结果不一定会被评估(因为懒惰)。

那么让我们看看IO monad 的实现......呃,其实你知道吗?我们不要。(它是深奥的魔术,硬连接到编译器中,因此它是特定于实现的。但这种现象绝不是IO独有的。让我们看一下Maybe的monad:

instance Monad Maybe where
  mx >>= f =
    case mx of
      Nothing -> Nothing
      Just  x -> f x
  return x = Just x

所以如果我做类似的事情

do
  x <- foobar
  return "hello"

x会得到评估吗?让我们看看。它脱糖为:

foobar >>= ( x -> return "hello")

那么这变成了

case foobar of
  Nothing -> Nothing
  Just  x -> Just "hello"

如您所见,foobar显然将被评估,因为我们需要知道结果是Nothing还是Just 。但是不会评估实际x,因为没有任何东西会查看它。

这与length评估列表节点的方式相同,但不是它们指向的列表元素。

相关内容

最新更新