Package ChasingBottoms
with its approxShow
can help you explore partially evaluated values:
$ cabal install ChasingBottoms
$ ghci
> import Test.ChasingBottoms.ApproxShow
> import Data.Function
> approxShow 10 (fix (1:))
"[1, 1, 1, 1, 1, 1, 1, 1, 1, _"
However, here we can’t use it directly: summation over Integer
s is strict, unlike (:)
which is used to build a list. Therefore another type should be used.
First, some imports (we also need to be able to derive Data
, so that approxShow
could be used to show our custom type):
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Monoid
import Data.Function
import Control.Applicative
import Test.ChasingBottoms.ApproxShow
The type itself (very basic), and its Num
instance:
data S = N Integer | S :+ S
deriving (Typeable, Data)
instance Num S where
(+) = (:+)
fromInteger = N
--other operations do not need to be implemented
Finally, the function:
f :: S -> Sum S
f = fix ((<>) <$> Sum <*>)
And here is how we can see what f
is doing with, say, a common number such as 1:
*Main> approxShow 5 (getSum (f 1))
"(N 1) :+ ((N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _))))"
Of course, it may be more interesting to watch the evolution:
*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 _) :+ (_ :+ _))))))