Recall that we defined goldbachPairs
as follows.
goldbachPairs g = [(p, k) | k <- takeWhile ((< g) . (*2) . (^2)) [1 .. ],
p <- [g - 2 * k * k], isPrime p]
Let's define a predicate satisfiesGoldbach
as follows.
satisfiesGoldbach g = not (null (goldbachPairs g))
So, for example,
> goldbachPairs 101
[(83,3),(29,6),(3,7)]
and
> satisfiesGoldbach 101
True
My question is: how many of the Goldbach pairs are computed before satisfiesGoldbach
returns
True
?
Here's a tool you can use to help you find out.
At the start of the file add the line
import Debug.Trace -- See https://hackage.haskell.org/package/base-4.9.0.0/docs/Debug-Trace.html
Then modify goldbachPairs
as follows
goldbachPairs g = [(p, k) | k <- takeWhile ((< g) . (*2) . (^2)) [1 .. ], trace ("k = " ++ show k) True,
p <- [g - 2 * k * k], isPrime p, trace ("Returning " ++ show (p, k)) True]
(The function show
in Haskell is like toString
in Java. It doesn't do output. It just converts its argument to a String
. We must call it to do String
concatenation (++
).)
Run both goldbachPairs
101
and satisfiesGoldbach
101
.
What's the difference in the trace output? Can you explain why. What does this have to do with Haskell being lazy?
Most importantly: how does Haskell manage to do what you see?