"takeWhile(<=(maxBound :: Word8))primes"挂起

Ign*_*rov 6 haskell

今天我想知道有多少素数符合这个范围Word8,但这个最微不足道的任务给了我一个意想不到的...... 没有结果.

? import Data.Numbers.Primes
? import Data.Word
? takeWhile (<= (maxBound :: Word8)) primes
[2,3,5,7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,53,55,59,61,71,73,
77,79,83,85,89,95,97,101,103,107,109,115,119,121,125,127,133,137,139,
145,149,151,157,161,163,167,173,175,179,185,187,191,197,199,203,205,
209,215,217,223,235^CInterrupted.
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,此评估不仅不会终止,而且所产生的数字也不是全部!

我继续围着这个案子跳舞:

? maxBound :: Word8
255

? takeWhile (<= 255) primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,
97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181
,191,193,197,199,211,223,227,229,233,239,241,251]

? takeWhile (<= (maxBound :: Word8)) [1..]
[1,2,3, {- ..., -} 253,254,255]
-- This of course works, so I do not present the consecutive
-- natural numbers inbetween 3 and 253.

? takeWhile (<= 255) $ take 255 primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,
97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181
,191,193,197,199,211,223,227,229,233,239,241,251]

? takeWhile (<= (maxBound  :: Word8)) $ take 255 primes
[2,3,5,7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,53,55,59,61,71,73,
77,79,83,85,89,95,97,101,103,107,109,115,119,121,125,127,133,137,139,
145,149,151,157,161,163,167,173,175,179,185,187,191,197,199,203,205,
209,215,217,223,235^CInterrupted.
Run Code Online (Sandbox Code Playgroud)

所以,takeWhile只有当我们避免maxBound或者primes.

我如何解释这些发现?


我使用最新的稳定stack快照和这个素数库.

Bar*_*icz 10

你的问题非常有趣,但它并不存在takeWhile; 它在primes:

既然primes能够返回你想要的任何类型,它的实现可能会在内部默默地使用该类型.所以,当你要求它返回Word8素数时,它在内部失败:

? take 20 (primes :: [Word8])
[2,3,5,7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,53,55]
Run Code Online (Sandbox Code Playgroud)

我想一个解决方法是使用固定类型的素数生成器(例如(primes :: [Int]),只是fromIntegral你的限制值.并且可能还会向库提交一个错误.


chi*_*chi 5

实际问题是由Bartek Banachewicz发现的.

但是请注意,谓词(<= (maxBound :: Word8))总是正确的.它等同于p:

p :: Word8 -> Bool
p x = x <= maxBound
Run Code Online (Sandbox Code Playgroud)

现在,重要的是x这里的参数(原始代码中隐含的)是一个Word8.因此,我们将任意数据Word8与可表示的最大数量进行比较Word8.这总是如此!

如果您需要数字类型转换,则必须明确.例如

takeWhile (<= fromIntegral (maxBound :: Word8)) (primes :: [Int])
Run Code Online (Sandbox Code Playgroud)

现在,隐含x是一个Int,并且fromIntegral正确地转变256::Word8256::Int.