为什么在不需要它的值时评估getLine?

时间:2016-02-17 17:25:32

标签: haskell

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

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

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

(我在GHCi中测试了两个案例)

由于

3 个答案:

答案 0 :(得分:4)

它的结果正在被使用,而不是你想象的方式。这消失了

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

因此getLine的结果仍然传递给函数\x -> return "hello"。 Monads本质上是关于一起排序行动(除此之外);即使以后没有使用结果,测序仍然会发生。如果不是这样,那么

main = do
    print "Hello"
    print "World"

不会作为一个程序执行任何操作,因为两次调用print的结果都没有被使用。

答案 1 :(得分:2)

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

getLine的结果 一个字符串。这是一个IO动作恰好“生成”一个字符串。确实没有评估该字符串,但是操作本身是(因为它出现在绑定到do的{​​{1}}块中),就副作用而言,这一切都很重要。< / p>

真的只是main。这不是一个函数,因此它实际上没有结果。

答案 2 :(得分:2)

现在要小心......; - )

getLine的结果不是字符串,它是“I / O命令对象”,如果你愿意的话。该代码实际上是去了

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

>>=运算符从现有的I / O命令对象和函数中构造出一个新的I / O命令对象......好的,这有点让你大吃一惊。重要的是,执行I / O操作(因为>>=的{​​{1}}的实现),但其结果不一定得到评估(因为懒惰)。

那么让我们来看看IO monad ......的实现,其实你知道吗?我们。 (这很神奇,很难连接到编译器中,因此它是特定于实现的。)但是这种现象并不是IO所独有的。我们来看看IO monad:

Maybe

所以,如果我做了像

这样的事情
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评估列表节点的方式相同,但不是它们指向的列表元素。