flawr
flawr

Reputation: 11628

creating tuples from infinite list

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

Answers (1)

Daniel Wagner
Daniel Wagner

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:

  1. take :: Int -> [a] -> [a]
  2. In f n, the use of take n p forces n :: Int.
  3. Because the arguments to order must have the same type, the calls order r n and order s n force r, s :: Int.
  4. (r, s) <- take n p forces p :: [(Int, Int)]
  5. 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

Related Questions