![](/img/trans.png)
[英]Why does ghci give me a type for “1 ++ 2” instead of ragequitting?
[英]Why does :p freeze in GHCi when I give it this corecursive value?
我已经定义了无限列表的无限列表pathCounts
和无限列表的有限列表pathCounts'
:
import Data.Function (fix)
nextRow xs = fix $ \ys -> zipWith (+) xs (0:ys)
pathCounts = repeat 1 : map nextRow pathCounts
pathCounts' = map (take 100) pathCounts
放入ghci,如果我根本没有评估,我可以成功使用:p
:
ghci> :p pathCounts
pathCounts = (_t1::[[Integer]])
ghci> :p pathCounts'
pathCounts' = (_t2::[[Integer]])
但是如果我部分地评估pathCounts'
,那么:p
在pathCounts
上冻结,同时仍然在pathCounts'
上pathCounts'
:
ghci> head . head $ pathCounts'
1
ghci> :p pathCounts'
pathCounts' = (1 : (_t4::[Integer])) : (_t5::[[Integer]])
ghci> :p pathCounts
^CInterrupted.
我希望:p pathCounts
打印相同:p pathCounts'
,因为我只是部分评估它。 为什么不工作?
我希望
:p pathCounts
打印相同:p pathCounts'
,因为我只是部分评估它。
啊,但那是有趣的一点! 事实上,你已经完全评估了pathCounts
(无限长)的头部。 让我们用一个稍小的例子来简化讨论:
> let v = repeat 1 :: [Int]
> head v
1
> :p v
^C
我声称在完全评估head v
,事实上v
也被完全评估。 这是因为,在存储器中, v
是循环单链表。 因此,如果您已经足够了解第一个元素,那么就没有什么可以评估了!
结果是当你要求:print
它时,GHC正式尝试构造一个表示结构的所有评估部分的字符串 - 显然不能,因为它永远不会停止遍历。 ( :p
根本没有办法表明在结构中共享。)
相比:
> let x = 1 :: Int; v = (x, x)
> fst v
1
> :p v
(1,1)
虽然您只要求评估v
的第一部分,但事实上所有的v
都已经在这里进行了评估,因此:p
打印全部 - 并不表示第一部分和第二部分之间存在共享。
现在,为什么pathCounts'
没有同样的问题? 那么,有一点是,尽管map f (repeat x) = repeat (fx)
是一个表示上正确的方程,但在Haskell的GHC实现中,该方程在操作上并不合理 - 并且:p
是关于操作的语义和拇指在指称语义上的鼻子。 特别是, map
不会(不能)观察repeat x
存在的共享; 因此它产生一个非循环的无限列表。 由于map f (repeat x)
具有较少的共享,因此强制map f (repeat x)
一部分不会导致完全评估的内存中表示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.