Today I was up to find out how many prime numbers there are that fit the bounds of Word8
, but this most trivial task gave me an unexpected... absence of result.
λ 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.
As you may see, not only does this evaluation not terminate, but the numbers yielded are not all prime!
I proceeded to dance around the case:
λ 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.
So, takeWhile
only works when we avoid either maxBound
or primes
.
How am I to interpret these findings?
I use the latest stable stack
snapshot and this primes library.
Your problem is quite interesting, but it's not in takeWhile
; it's in primes
:
Since primes
is able to return whatever type you want, its implementation probably silently uses that type internally. So, when you ask it to return Word8
primes, it fails internally:
λ take 20 (primes :: [Word8])
[2,3,5,7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,53,55]
I suppose a workaround is to use a fixed type for the primes generator (e.g. (primes :: [Int])
, and just fromIntegral
your limit value. And possibly file a bug to the library as well.
The actual issue was found by Bartek Banachewicz above.
However, note that the predicate (<= (maxBound :: Word8))
is always true.
It is equivalent to p
where:
p :: Word8 -> Bool
p x = x <= maxBound
Now, the important thing is that the x
argument here (which is implicit in the original code) is a Word8
. So, we are comparing an arbitrary Word8
to the maximum number representable in Word8
. This is always true!
If you need a numeric type conversion, you have to be explicit. E.g.
takeWhile (<= fromIntegral (maxBound :: Word8)) (primes :: [Int])
Now, the implicit x
is an Int
, and fromIntegral
correctly turns 256::Word8
into 256::Int
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With