Kyle
Kyle

Reputation: 3042

Trying to trace a function with if

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

Answers (1)

Chai T. Rex
Chai T. Rex

Reputation: 3020

The immediate issue

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

Additional tips

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 anses.


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

Related Questions