了解如何:冲刺和列表评估在haskell中有效

时间:2016-08-17 10:57:40

标签: list haskell evaluation

我正在研究haskell book,我明白:sprint x用于打印x的元素已被评估,而元素则没有(未被表达的元素由'_')。

书中提供的一个例子,

Prelude> let blah = enumFromTo 'a' 'z' 
Prelude> :sprint blah 
blah = _

Prelude> take 1 blah 
"a" 
Prelude> :sprint blah 
blah = 'a' : _

为了测试不同的输入,我在GHCi中做了这个: -

prelude> let b = [1,2,3,4,5]
prelude> :sprint b
b = _
prelude> take 1 b
[1]
prelude> :sprint b
b = _

最后一个命令中:sprint b的输出不应该是b = 1 : _,因为我们在使用命令take 1 b时只评估单个列表项和cons运算符?但它显示了上面的输出。这是怎么发生的?输出不应该类似于String类型的输出吗?

编辑:我一直在尝试更多并得到这个结果: -

prelude> let b = [1..10] :: [Int]
prelude> :sprint b
b = _
prelude> take 3 b
[1,2,3]
prelude> :sprint b
b = 1 : 2 : 3 : _

好吧,我最初的猜测是,这是因为我正在构建两个列表的方式?一个是使用范围而另一个是通过明确地声明它的元素(它依次通过在元素上递归使用cons':'构造函数来创建列表)

1 个答案:

答案 0 :(得分:6)

:sprint的行为可能有点棘手。在这种情况下,请查看x的类型:

> :t x
x :: Num t => [t]

因为它是多态的,所产生的实际值取决于您需要的Num的特定实例。因此,x的行为更像是一个函数,当它可以确定您希望元素具有什么类型时,它将生成列表[1,2,3,4,5]

现在你可能会想,“好吧,我会制作一个非多态的列表”,所以你试试这个:

> let x = [1,2,3,4,5 :: Int]
> :t x
x :: [Int]
> :sprint x
x = [1,2,3,4,5]

到底是什么?如果你考虑一下,这是有道理的。我们已经明确告诉ghci列表是什么。它不是可以取消评估它,然后再重新评估它。 (无论如何这都是浪费。)但是让我们看看当我们尝试将函数映射到x时会发生什么:

> let y = map (+1) x
> :sprint y
y = _
> take 1 y
[2]
> :sprint y
y = 2 : _

正如所料!

希望有所帮助。懒惰的评估是关于Haskell的一个棘手的问题(当它变得很重要时)。