这无疑是一个讽刺性的问题 What does this list permutations implementation in Haskell exactly do?
假设
perms [] = [[]]
perms xxs = [ (y:ys) | ( y, xs ) <- pix xxs , ys <- perms xs ]
--where
pix [] = []
pix ( x:xs ) = ( x , xs ) : [ ( y, x : ys ) | ( y, ys ) <- pix xs ]
Twan van Laarhoven写道&#34;这个功能的第一件事是从整个列表中选择第一个元素,这根本不是懒惰的。&#34;是当然 !但我很困惑 -
我不明白为什么ghci会做以下事情:
*Main> let p = perms [1..]
*Main> let hs = map head p
*Main> take 1 hs
*** Exception: stack overflow
为什么不能打印[1]?
唉...
彼得
评论答案:
正如我在对卡斯滕回答的回复中所说的那样,我已经推理过&#39;我的
*Main> let hs = map head p
*Main> take 1 hs
与Haskell的懒惰一起,将允许ghci不以烫发中的y(y:ys)计算ys,因为上面只有&#39;想要&#39;第一个&#39;的价值;总之,我认为我根本没有计算第一个烫发期[1 ..]。 但是,正如卡斯滕和里德巴顿实际上指出的那样,懒惰是除了这一点,我的论点是错误的。
如果
,请添加(并且,我希望,不要破坏)他们的答案 ans = take 1 hs
然后,由于perms定义中的列表理解,
ans is in the image of some function from the Cartesian product
(pix [1..]) X perms [2..].
但我怎么知道笛卡尔积,我的函数域,不是空集?因为,否则,ans不存在......(也就是说,我怎么知道烫发的第一个术语[1 ..]存在?或者,正如Reid Barton更简洁地说出来的那样,我怎么知道烫发[1。 。]不是空的?)
如果且每个因素都不为空,则产品不为空。我知道第一个不是空的(检查!) - 但我怎么知道烫发[2 ..]因子不是空的?哦 - 唉,通过递归,我已经死了。
答案 0 :(得分:4)
好吧,让我们看看它必须做什么(让我们使用GHCi调试器)
λ> :break perms
Breakpoint 0 activated...
λ> perms [1..]
Stopped at perms
λ> :step
Stopped at RHS perms xxs
xxs :: [Integer] = 1 : _
λ> :step
Stopped at RHS perms xxs (comprehension)
xxs :: [Integer] = 1 : _
λ> :step
Stopped at pix
λ> :step
Stopped at RHS pix (x:xs)
x :: Integer = 1
xs :: [Integer] = _
λ> :step
Stopped at RHS perms xxs (comprehension)
xs :: [t] = _
λ> :step
Stopped at perms
λ> :step
Stopped at rhs perms xxs
_result :: [[Integer]] = _
xxs :: [Integer] = 2 : _
...
我试图稍微翻译一下这个位置,除了最后一个_result
之外我已经删除了(你看到它仍然没有在任何WHNF列表中)
重要的一行是最后一行:你能看到你和开头一样走进了同一条线,但现在你的无限列表的尾巴?
那是因为你画了ys <- perms xs
,如果你再继续,你会看到xxs = 3 : _
......
最后,你必须在获得任何结果之前遍历所有列表 - 这当然是不可能的。
take 1 $ perm [1..]
不会在此更改任何内容,因为它必须将上述表达式的结果评估为_:_
或[]
,但正如您所看到的那样 - 当然,如果你添加像
first () = take 1 $ perms [1..]
然后再做
:break first
first ()
: step
在ghci中 - 我认为这是一种有趣的探索方式 - 虽然它可能有点乏味
懒惰是不容易的概念是的,原则上你的推理并不坏 - 但take
和map
都需要将给定的列表解构为_:_
之类的东西,现在这意味着你需要至少看到列表的(:)
构造函数(或[]
) - 但是这里(我试图用调试会话向你展示) chunk 从未到达此状态(s the
_ result`部分) - 在Haskell中没有问题,但是使用您的算法/算法的实现细节。
要查看可以工作,您只需要查看Data.List
中的permutations
- 如果您尝试使用此代码运行代码,那么它只会起作用细:
λ> import Data.List (permutations)
λ> map head . take 1 $ permutations [1..]
[1]
λ>
这样做:
λ> import Data.List (permutations)
λ> take 1 $ permutations [1..]
但当然这将继续打印直到时间结束(记忆,无论如何)
如果您有兴趣,也可以查看implementation of permutations
。
答案 1 :(得分:2)
你怎么知道perms [1..]
是非空的?