Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"takeWhile (<= (maxBound :: Word8)) primes" hangs

Tags:

haskell

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.

like image 556
Ignat Insarov Avatar asked Oct 04 '17 10:10

Ignat Insarov


2 Answers

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.

like image 189
Bartek Banachewicz Avatar answered Oct 25 '22 10:10

Bartek Banachewicz


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.

like image 26
chi Avatar answered Oct 25 '22 12:10

chi