2013-04-05 12 views
6

Say Mam funkcji (nie ma żadnego praktycznego zastosowania, tylko zainteresowanie akademickiej, stąd dziwny sposób, żeby to napisać, ze monoids, aplikacyjnych funktorów i kombinatorów fixpoint)debugowanie nieskończony Sum w Haskell

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

To typechecks, ale nie mogę być pewien, że robi to, co oczekuje się zrobić, zanim mogę go przetestować.

Jak można testować i/lub debugować? Mam na myśli coś takiego, jak zobaczenie wyniku po kilku iteracjach, jak to jest możliwe z take 10 [1..].

wiem trochę o prostych obiektów debugowanie ghci jak :break i :step, ale kroki do obliczenia nie kończącej więc nie mogę niczego sprawdzać (to nawet problematyczne ^C it). I nie wiem, jak korzystać z trace z Debug moduł w tej funkcji albo.

Wszelkie wskazówki byłyby mile widziane.

+0

Cóż, łatwo widzisz, co robi, jeśli rozszerzysz go do 'f = fix (\ g -> \ x -> Suma x <> gx)' – phg

Odpowiedz

10

Pakiet ChasingBottoms z jego approxShow może pomóc zbadać częściowo poddanych ocenie wartości:

$ cabal install ChasingBottoms 
$ ghci 
> import Test.ChasingBottoms.ApproxShow 
> import Data.Function 
> approxShow 10 (fix (1:)) 
"[1, 1, 1, 1, 1, 1, 1, 1, 1, _" 

Jednak tutaj nie możemy użyć go bezpośrednio: podsumowanie ponad Integer s jest ścisłe, w przeciwieństwie (:) która służy do zbuduj listę. Dlatego należy użyć innego typu.

Po pierwsze, niektóre import (my również potrzebujemy, aby móc czerpać Data, tak że approxShow mogą być wykorzystane, aby pokazać nasze typ niestandardowy):

{-# LANGUAGE DeriveDataTypeable #-} 

import Data.Data 
import Data.Monoid 
import Data.Function 
import Control.Applicative 
import Test.ChasingBottoms.ApproxShow 

Sam typ (bardzo prosty), a jego Num przykład:

data S = N Integer | S :+ S 
    deriving (Typeable, Data) 

instance Num S where 
    (+) = (:+) 
    fromInteger = N 
    --other operations do not need to be implemented 

Na koniec, funkcja:

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

A oto w jaki sposób możemy zobaczyć, co f robi z, powiedzmy, wspólny numer taki jak 1:

*Main> approxShow 5 (getSum (f 1)) 
"(N 1) :+ ((N 1) :+ ((N 1) :+ ((N _) :+ (_ :+ _))))" 

Oczywiście, może być bardziej interesujące obserwować ewolucję:

*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 _) :+ (_ :+ _)))))) 
+1

+1, dziękuję za udostępnienie –

+0

Dzięki, nie wydaje mi się być jest w stanie zastosować go tak, jak jest do mojej funkcji: 'approxShow 5 (f 1)' wynikiem jest 'No instance for (Data.Data.Data (Sum Integer))'. I robienie 'approxShow 10 (getSum (f 1))' również się nie kończy. – dmedvinsky

+0

@dmedvinsky: Przepraszam, mój zły (szczerze mówiąc, nigdy wcześniej nie słyszałem o "Sumie" i myślałem, że to jakiś niestandardowy typ, więc nie zawracałem sobie głowy sprawdzaniem). Odpowiedź zaktualizowana. – Artyom