Haskell 逐步显示还原过程
我正在Haskell的SICP中做练习1.20,想知道是否有一种方法可以以编程方式可视化缩减步骤?它应该是这样的: 除了“b是6”之外,我想看到未经计算的(或货币化的)表达式,如Haskell 逐步显示还原过程,haskell,Haskell,我正在Haskell的SICP中做练习1.20,想知道是否有一种方法可以以编程方式可视化缩减步骤?它应该是这样的: 除了“b是6”之外,我想看到未经计算的(或货币化的)表达式,如gcd'40(rem 206 40) 示例程序: import Debug.Trace gcd' a b = if b == 0 then a else trace ("b is " ++ show b) gcd' b (a `rem` b) main = print $ gc
gcd'40(rem 206 40)
示例程序:
import Debug.Trace
gcd' a b =
if b == 0
then a
else trace ("b is " ++ show b) gcd' b (a `rem` b)
main = print $ gcd' 206 40
这个问题的原始定义可以在这里找到:首先,让我们重写你的
gcd
函数,为了可读性,我将去掉跟踪:
gcd :: Int -> Int -> Int
gcd a 0 = a
gcd a b = gcd b (a `rem` b)
请注意,在这个函数(以及您编写的函数)中,我们必须知道b
是否为零,然后才能给出答案。这意味着gcd
在其第二个参数中是严格的。现在减少gcd 206 40应该非常简单:
gcd 206 40
gcd 40 (206 `rem` 40)
gcd 40 6
gcd 6 (40 `rem` 6)
gcd 6 4
gcd 4 (6 `rem` 4)
gcd 4 2
gcd 2 (4 `rem` 2)
gcd 2 0
2
执行此操作的方法是使用Writer
monad。您可以使用它轻松地将日志功能添加到代码中:
import Control.Monad.Writer
gcd' :: Int -> Int -> (Int, [String])
gcd' a b = runWriter $ gcdW a b
where
gcdW :: Int -> Int -> Writer [String] Int
gcdW a 0 = return a
gcdW a b = do
tell ["b is " ++ show b]
gcdW b (a `rem` b)
main :: IO ()
main = do
let (result, logs) = gcd' 206 40
mapM_ putStrLn logs
print result
此实现所做的是将GCD算法封装在Writer
monad中,用于在许多计算中聚合某种结果。通常,它用于记录消息或输出中间结果。这里我们想要的是以漂亮的打印形式获得b
的每个中间值的结果和日志。由于每个消息都是一个字符串
,因此我们希望建立一个字符串
列表,这就是为什么它必须在tell
中用方括号括起来的原因。算法的其余部分基本相同,只需在b==0时返回a
,否则以与之前完全相同的方式执行递归。gcd'
函数只是将Writer
monad包装起来,这样对用户来说是透明的。然后,我们可以得到结果和日志消息,并根据需要打印出来。trace
功能通常仅保留用于调试,特别是因为它使用了unsafePerformIO
。使用Writer
monad,您可以重复使用此代码,而无需担心每次打印出步骤。以编程方式,不是。或者至少不容易。Haskell的AST比Scheme的更不容易发生这种事情。