2013-04-05 18 views
6

Dire Ho una funzione (che non ha alcuna applicazione pratica, solo un interesse accademico, in tal modo strano scriverlo, con monoidi, funtori applicative e combinatori di punto fisso)debug somma infinita in Haskell

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

Si tratta di errori di battitura, ma non posso essere sicuro che faccia ciò che è necessario fare prima di poterlo verificare.

Come si può eseguire il test e/o il debugging? Intendo qualcosa come vedere il risultato dopo diverse iterazioni come è possibile con take 10 [1..].

so un po 'su semplici strutture di debug di ghci come :break e :step, ma passi nel calcolo non-terminazione quindi non posso controllare nulla (è ancora problematico ^C esso). E non riesco a capire come usare il modulo Debug in questa funzione.

Qualsiasi suggerimento sarebbe apprezzato.

+0

Bene, puoi facilmente vedere cosa fa se lo espandi in 'f = fix (\ g -> \ x -> Sum x <> gx)' – phg

risposta

10

pacchetto ChasingBottoms con la sua approxShow può aiutare a esplorare i valori parzialmente valutati:

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

Tuttavia, qui non possiamo usare direttamente: sommatoria sopra Integer s è rigorosa, a differenza (:) che viene utilizzato per costruire una lista. Quindi dovrebbe essere usato un altro tipo.

primo luogo, alcune importazioni (abbiamo anche bisogno di essere in grado di ricavare Data, in modo che approxShow potrebbero essere utilizzati per mostrare il nostro tipo personalizzato):

{-# LANGUAGE DeriveDataTypeable #-} 

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

Il tipo in sé (molto semplice), e la sua Num esempio:

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

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

Infine, la funzione:

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

Ed ecco come possiamo vedere ciò che f sta facendo con, diciamo, un numero comune come ad esempio 1:

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

Naturalmente, può essere più interessante osservare l'evoluzione:

*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, grazie per aver condiviso –

+0

Grazie, non mi sembra di essere in grado di applicarlo come è per la mia funzione però: 'approxShow 5 (f 1)' risulta in 'Nessuna istanza per (Data.Data.Data (Sum Integer))'. E fare 'approxShow 10 (getSum (f 1))' non termina neanche. – dmedvinsky

+0

@dmedvinsky: scusa, mia cattiva (a dire il vero, non ho mai sentito parlare di 'Sum' prima e ho pensato che fosse un tipo personalizzato, quindi non mi ero preso la briga di controllare). Risposta aggiornata – Artyom