为什么不能打印整数的第一个排列的头部,计算出“选择风格”?

时间:2015-06-02 03:06:29

标签: haskell stack-overflow ghci

这无疑是一个讽刺性的问题 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 ..]因子不是空的?哦 - 唉,通过递归,我已经死了。

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中 - 我认为这是一种有趣的探索方式 - 虽然它可能有点乏味

回答你的评论

懒惰是不容易的概念是的,原则上你的推理并不坏 - 但takemap都需要将给定的列表解构为_:_之类的东西,现在这意味着你需要至少看到列表的(:)构造函数(或[]) - 但是这里(我试图用调试会话向你展示) 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..]是非空的?