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
我不确定为什么if语句会失败
error: parse error on input `if'
|
37 | if (r == 0) then let ans = ans*ans `mod` m
| ^^
如何跟踪具有if语句的函数?
答案 0 :(得分:5)
要回答您的紧迫问题,您需要in
和let
一起使用(下面代码中第三行的开头):
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
使用let ans =
时,您正在定义ans
,因此等号右侧的任何ans
均指代左侧的ans
等号,没有其他地方定义的ans
。因此,这将失败:
let ans = ans*ans `mod` m
这就像无所不在地说let x = x*x `mod` m
。它只会提供无限递归,因此请为两个ans
使用两个不同的变量名。
第三,更简单的方法是使用traceShowId :: Show a => a -> a
,该方法跟踪具有Show
实例的值。 traceShowId x
的值为x
,因此您可以在想要使用x
的地方使用它。它还跟踪x
。例如:
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
用这种方式打字要少得多。如果箭头很重要,也可以使用trace "vvv" . traceShowId $
。