Debugging an infinite amount in Haskell

Let's say that I have a function (it does not have a practical application, just academic interest, thus, a strange way to write it, with monoids, applicative functors and fixed point combinations)

f :: Num a => a -> Sum a f = fix ((<>) <$> Sum <*>) 

These are typechecks, but I cannot be sure that he is doing what is expected before I can check it.

How could testing be done and / or debugged? I mean something like looking at the result after several iterations, as is possible with take 10 [1..] .

I am a little versed in simple ghci debugging ghci such as :break and :step , but it goes into the calculation endlessly, so I can’t check anything (this is even problematic for ^C it). And I cannot figure out how to use trace from the Debug module in this function.

Any pointers would be appreciated.

+6
source share
1 answer

The ChasingBottoms package with approxShow can help you learn partially estimated 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, we cannot use it directly here: the summation over Integer is strict, unlike (:) , which is used to build the list. Therefore, a different type should be used.

Firstly, some import operations (we also need to be able to output Data , so approxShow can be used to display 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 simple) 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 does, for example, with a total 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 observe 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 _) :+ (_ :+ _)))))) 
+10
source

All Articles