Reputation: 11628
When trying to solve this challenge I stumbled upon something I was not able to explain myself.
First I generate an infinite list of prime numbers as follows:
primes = [n|n<-[2..],product[1..n-1]`rem`n==n-1]
This has the inferred type [Integer]
so Int-overflow should not be a problem.
Then I try to make 2-tuples of subsequent primes (goal: [(2,3),(5,7),...]
). To achieve this I wrote another function:
listtotuples l=[ (l!!i, l!!(i+1) ) |i<-[0,2..]]
Strangely this listtotuples
function seems to work fine on e.g. [0..]
, but it just stops working when I apply it to primes
, the output is just (after interrupting)
[(2,3),(5,7),(11,13),(Interrupted.
I do not understand why this happens, can anyone explain?
EDIT: This does not only happen when trying to output the infinite list, but also e.g. using take 10 $ listtotuples primes
in Prelude after having loaded a file with the two lines from above. It does get stuck at the exact same point.
I am using Windows 7 with GHCi 7.10.2.
EDIT2: The full contents of my file are as follows:
order p m=head[n-1|n<-[0..],mod m (p^n)>0]
primes = [n|n<-[2..],product[1..n-1]`rem`n==n-1]
listtotuples l=[ (l!!i, l!!(i+1) ) |i<-[0,2..]]
p=listtotuples primes
f n=product[r^(order s n) * s^(order r n)|(r,s)<-take n p]
The problem disappears as soon as I comment/remove the last line (the function f
, but I still think this is very strange, as f
is not called and does not have anything todo with the functions above. Also if I replace take n p
in the function f
with [(2,3)]
everything works as defined.
Upvotes: 3
Views: 168
Reputation: 152707
The addition of f
forces your primes to have type Int
, which does overflow during the factorial operation. The reasoning goes like this:
take :: Int -> [a] -> [a]
f n
, the use of take n p
forces n :: Int
.order
must have the same type, the calls order r n
and order s n
force r, s :: Int
.(r, s) <- take n p
forces p :: [(Int, Int)]
p = listtotuples primes
forces primes :: [Int]
Simple fixes include breaking steps 2 or 3 above; use take (fromInteger n) p
to break step 2 or order s (fromIntegral n)
and order r (fromIntegral n)
to break step 3.
...and now you know why adding top-level type signatures is considered a best practice. =)
Upvotes: 6