【发布时间】:2021-01-03 23:19:46
【问题描述】:
我有以下数据类型,它编码任意实数:
newtype ArbReal = ArbReal {approximate :: Word -> Integer}
我有以下函数,它找到实数收敛序列的极限:
inexactToReal :: (Word -> ArbReal) -> ArbReal
inexactToReal f = ArbReal $ \n -> let
ArbReal g = f n
in g n
我实现了一个常数,十的自然对数:
ln10 :: ArbReal
ln10 = inexactToReal $ \n -> if 0 == n
then 2
else let
halfN = ceiling (n % 2)
a = inexactToReal $ \m -> go (2 * logBaseZ m 2) 1 (4 / 10 ^ halfN)
in pi / (2 * a * fromInteger halfN)
where
go n a b = let
newA = (a + b) / 2
in if 0 == n
then newA
else go (n-1) newA (sqrt (a * b))
但这有一些错误。我认为这陷入了无限循环。所以我想把它变成一个调试程序。这就是问题所在。考虑上面go 的以下变体:
debugAGM :: Word -> ArbReal -> ArbReal -> IO ArbReal
debugAGM n a b = let
newA = (a + b) / 2
in if 0 == n
then putStrLn "Iteration complete." >> return newA
else do
putStrLn ("debugAGM iteration: n = " ++ show n)
debugAGM (n-1) newA (sqrt (a * b))
IO 太多了。没有inexactToReal 的变体可以处理这个问题。
考虑一下:
debugAGM :: Word -> ArbReal -> ArbReal -> (ArbReal, IO ())
debugAGM n a b = let
newA = (a + b) / 2
in if 0 == n
then (newA, putStrLn "Iteration complete.")
else let
(x, action) = debugAGM (n-1) newA (sqrt (a * b))
in (x, putStrLn ("debugAGM iteration: n = " ++ show n) >> action)
IO 太少了。 IO 操作与返回值并行。没有inexactToReal 的变体可以处理这个问题。
总之,我必须以某种方式转义IO,以便实现以下目标:
-
返回的值,本质上是一个函数,必须是纯的。
-
但还必须有一个
IO操作,该操作取决于返回函数的潜在参数。
如何做到这一点?命令式语言可以轻松做到这一点,真是令人心碎。
【问题讨论】:
-
看看
Debug.Trace,它对于调试此类问题非常有用。 Audrey Tang 将Debug.Trace描述为“参照透明绿洲中的清新沙漠” -
我不太懂
inexactToReal的实现。如果你去掉新类型,并用类型参数替换 Word 和 Integer,它是inexactToReal :: (a -> a -> b) -> a -> b; inexactToReal f x = f x x。这与找到序列的极限有何对应? -
另外,
ln10如何进行类型检查?它似乎经常将 ArbReal 与数字类型混合在一起,但没有声明 Num 实例。 -
@amalloy 我实现了
instance Num ArbReal,但这涉及到太多的野蛮数学,无法在此处展示。 -
@amalloy 构造函数
ArbReal仅标记具有渐近固定收敛速度的柯西序列,因此inexactToReal有效地计算了一个极限。
标签: debugging haskell io monads io-monad