6

私が関数を持っているとしましょう (それには実用的なアプリケーションはなく、学術的な興味があるだけです。したがって、モノイド、アプリケーション ファンクター、フィックスポイント コンビネーターを使用して、奇妙な書き方をします)

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

型チェックを行いますが、テストする前に期待どおりの動作をするかどうか確信が持てません。

それをテストおよび/またはデバッグするにはどうすればよいですか? で可能なように、数回繰り返した後に結果を見るようなものですtake 10 [1..]

やのghciような単純なデバッグ機能については少し知っていますが、非終了計算にステップインするため、何も調べることができません (問題になることさえあります)。また、この関数でfrom moduleを使用する方法もわかりません。:break:step^CtraceDebug

任意のポインタをいただければ幸いです。

4

1 に答える 1

10

パッケージ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, _"

ただし、ここではそれを直接使用することはできません。リストの作成に使用されるものとは異なり、 s の合計Integerstrictです。(:)したがって、別のタイプを使用する必要があります。

最初に、いくつかのインポート (カスタム型を表示するために使用できるように、派生できるようにする必要もあります) 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 _) :+ (_ :+ _))))))
于 2013-04-05T12:52:42.383 に答える