ChasingBottoms
带有它的包approxShow
可以帮助您探索部分评估的值:
$ cabal install ChasingBottoms
$ ghci
> import Test.ChasingBottoms.ApproxShow
> import Data.Function
> approxShow 10 (fix (1:))
"[1, 1, 1, 1, 1, 1, 1, 1, 1, _"
但是,这里我们不能直接使用它:对Integer
s 求和是严格的,不像(:)
用于构建列表。因此应使用另一种类型。
首先,一些导入(我们还需要能够派生Data
,以便approxShow
可以用来显示我们的自定义类型):
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Monoid
import Data.Function
import Control.Applicative
import Test.ChasingBottoms.ApproxShow
类型本身(非常基本)及其Num
实例:
data S = N Integer | S :+ S
deriving (Typeable, Data)
instance Num S where
(+) = (:+)
fromInteger = N
--other operations do not need to be implemented
最后,函数:
f :: S -> Sum S
f = fix ((<>) <$> Sum <*>)
下面是我们如何看到f
一个常见的数字(例如 1)在做什么:
*Main> approxShow 5 (getSum (f 1))
"(N 1) :+ ((N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _))))"
当然,观察演变可能会更有趣:
*Main> Control.Monad.forM_ [0..7] $ \i -> putStrLn $ approxShow i (getSum (f 1))
_
_ :+ _
(N _) :+ (_ :+ _)
(N 1) :+ ((N _) :+ (_ :+ _))
(N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _)))
(N 1) :+ ((N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _))))
(N 1) :+ ((N 1) :+ ((N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _)))))
(N 1) :+ ((N 1) :+ ((N 1) :+ ((N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _))))))