Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 逐步显示还原过程_Haskell - Fatal编程技术网

Haskell 逐步显示还原过程

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

我正在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 $ 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的更不容易发生这种事情。