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

Cha*_*dan 3 evaluation haskell list

我正在研究haskell书,我理解:sprint x用于打印x的元素已经被评估,而元素则没有(那些不是由'_'表示的).

书中提供的一个例子,

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

Prelude> take 1 blah 
"a" 
Prelude> :sprint blah 
blah = 'a' : _
Run Code Online (Sandbox Code Playgroud)

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

prelude> let b = [1,2,3,4,5]
prelude> :sprint b
b = _
prelude> take 1 b
[1]
prelude> :sprint b
b = _
Run Code Online (Sandbox Code Playgroud)

:sprint b最后一个命令的输出不应该是b = 1 : _因为我们在使用命令时只评估一个列表项和一个cons运算符take 1 b?? 但它显示了上面的输出.这是怎么发生的?输出不应该类似于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 : _
Run Code Online (Sandbox Code Playgroud)

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

use*_*560 6

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

> :t x
x :: Num t => [t]
Run Code Online (Sandbox Code Playgroud)

因为它是多态的,所产生的实际值取决于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]
Run Code Online (Sandbox Code Playgroud)

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

> let y = map (+1) x
> :sprint y
y = _
> take 1 y
[2]
> :sprint y
y = 2 : _
Run Code Online (Sandbox Code Playgroud)

正如所料!

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

  • 值得补充的是,如果你做`:set -XMonomorphismRestriction`,第一个问题就会消失.使用`:sprint`的一些例子,例如在*Parallel和Concurrent Haskell*书中,早于ghci中的默认使用`-XNoMonomorphismRestriction`,因此引起了这个麻烦.在摆弄`:sprint`之前,你可能应该总是把它关掉,或者用签名坚持不懈 (2认同)