Reputation: 3042
expmod :: Integer -> Integer -> Integer -> Integer
expmod a n m | trace (show (a n m)) False = undefined
expmod a 0 m = 1
expmod a n m = let (q,r) = divMod n 2
ans = expmod a q m
if r == 0 then let ans = ans*ans `mod` m
in trace ("-->" ++ show ans) ans
else let ans = ans*ans*a `mod` m
in trace ("-->" ++ show ans) ans
I'm not sure why it's failing at the if statement
error: parse error on input `if'
|
37 | if (r == 0) then let ans = ans*ans `mod` m
| ^^
How do you trace a function that has if statements?
Upvotes: 1
Views: 129
Reputation: 3020
To answer your immediate question, you need an in
to go with your let
(the beginning of the third line in the code just below):
expmod a n m = let (q,r) = divMod n 2
ans = expmod a q m
in if r == 0 then let ans = ans*ans `mod` m
in trace ("-->" ++ show ans) ans
else let ans = ans*ans*a `mod` m
in trace ("-->" ++ show ans) ans
When you use let ans =
, you're defining ans
, so any ans
on the right of the equal sign will refer to the ans
on the left side of the equal sign, not any ans
defined elsewhere. Thus, this will fail:
let ans = ans*ans `mod` m
It's just like saying let x = x*x `mod` m
out of nowhere. It'll just give infinite recursion, so use a two different variable names for the two ans
es.
Thirdly, an easier way is to use traceShowId :: Show a => a -> a
, which traces a value that has a Show
instance. traceShowId x
evaluates to x
, so you can use it where you'd want to use x
. It also traces x
. For example:
expmod a n m = let (q,r) = divMod n 2
ans = expmod a q m
in traceShowId $ if r == 0 then ans*ans `mod` m
else ans*ans*a `mod` m
Much less typing that way. You can also use trace "vvv" . traceShowId $
if the arrows were important.
Upvotes: 4