为什么:当我给它这个核心值时,p冻结在GHCi中?

时间:2014-02-12 15:34:22

标签: haskell ghci corecursion

我已经定义了无限列表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'

ghci> head . head $ pathCounts'
1
ghci> :p pathCounts'
pathCounts' = (1 : (_t4::[Integer])) : (_t5::[[Integer]])
ghci> :p pathCounts
^CInterrupted.

我希望:p pathCounts:p pathCounts'打印相同,因为我只对其进行了部分评估。为什么不起作用?

1 个答案:

答案 0 :(得分:8)

  

我希望: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'会将其全部打印出来 - 而且并非如此。 t表示第一和第二部分之间存在的共享。

现在,map f (repeat x) = repeat (f x)怎么会遇到同样的问题呢?好吧,有一点是,尽管:p是一个指称正确的方程,但在Haskell的GHC实现中,该方程在操作上并不合理 - map完全与操作语义有关。并且在指称语义上嗤之以鼻。特别是,repeat x没有(不能)观察map f (repeat x)中存在的共享;因此它产生一个非循环的无限列表。由于map f (repeat x)共享较少,因此强制部分dim i as integer 'puts the list otems at the end of the previous row for i = 1 to Cells(Rows.Count, "A").End(xlUp).Row if not range("A" & i) Like "A#" then if range("E" & i - 1) = "" Then'I assumed only 3 possible bullets, but suit this to your liking. If there are many bullets put this in a loop. range("E" & i - 1) = range("A" & i) ElseIf range("E" & i - 1)(,2) = "" Then range("E" & i - 1)(,2) = range("A" & i) ElseIf range("E" & i - 1)(,3) = "" Then range("E" & i - 1)(,3) = range("A" & i) Rows("i").delete Shift:=xlUp 'deletes the line end if next 不会导致内存中的表示完全评估。