Voglio realizzare l'istanza applicativa regolare per gli elenchi, usando il mio customly elenco definito:esempio applicativo di List viene eseguito sempre nella prova di legge composizione con QuickCheck/Checkers
import Control.Monad
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
data List a =
Nil
| Cons a (List a)
deriving (Eq, Ord, Show)
instance Functor List where
fmap f (Cons x xs) = Cons (f x) (fmap f xs)
fmap f Nil = Nil
instance Applicative List where
pure x = Cons x Nil
(<*>) Nil _ = Nil
(<*>) _ Nil = Nil
(<*>) (Cons f fs) xs = (+++) (fmap f xs) (fs <*> xs)
(+++) :: List a -> List a -> List a
(+++) (Cons x Nil) ys = Cons x ys
(+++) (Cons x xs) ys = Cons x xs'
where xs' = (+++) xs ys
instance Arbitrary a => Arbitrary (List a) where
arbitrary = sized go
where go 0 = pure Nil
go n = do
xs <- go (n - 1)
x <- arbitrary
return (Cons x xs)
instance (Eq a) => EqProp (List a) where
(=-=) = eq
main = do
let trigger = undefined :: List (Int, String, Int)
quickBatch $ applicative trigger
Il mio codice supera tutti i test applicativi in Checkers tranne uno, la legge sulla composizione. Nessun errore si verifica durante il test della legge sulla composizione, ma non finisce mai.
Il mio codice si ripresenta eternamente in un modo che non sono in grado di vedere, o è solo veeeramente lento per testare la legge sulla composizione?
Questo è il messaggio di errore ricevo se Control-C durante l'esecuzione Dama:
applicative:
identity: +++ OK, passed 500 tests.
composition: *** Failed! Exception: 'user interrupt' (after 66 tests):
Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> Nil))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> (Cons <function> Nil))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
Cons (-61) (Cons (-24) (Cons 56 (Cons (-10) (Cons 28 (Cons 5 (Cons (-5) (Cons 33 (Cons 18 (Cons 47 (Cons 43 (Cons 43 (Cons (-58) (Cons 35 (Cons (-52) (Cons (-52) (Cons (-41) (Cons 3 (Cons (-7) (Cons (-53) (Cons (-22) (Cons (-20) (Cons (-12) (Cons 46 (Cons (-53) (Cons 35 (Cons (-31) (Cons (-10) (Cons 43 (Cons (-16) (Cons 47 (Cons 53 (Cons 22 (Cons 8 (Cons 1 (Cons (-64) (Cons (-39) (Cons (-57) (Cons 34 (Cons (-31) (Cons 20 (Cons (-39) (Cons (-47) (Cons (-59) (Cons 15 (Cons (-42) (Cons (-31) (Cons 4 (Cons (-62) (Cons (-14) (Cons (-24) (Cons 47 (Cons 42 (Cons 61 (Cons 29 (Cons (-25) (Cons 30 (Cons (-20) (Cons 16 (Cons (-30) (Cons (-38) (Cons (-7) (Cons 16 (Cons 19 (Cons 20 Nil))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
homomorphism: +++ OK, passed 500 tests.
interchange: +++ OK, passed 500 tests.
functor: +++ OK, passed 500 tests.
Se una delle funzioni è lento, credo che sia il (+++)
, ma io non so come GHC esegue il codice abbastanza bene da capire perché.
Aggiornamento:
La legge composizione è:
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
Che posso mostrare opere con il mio codice per semplici esempi:
Cons (+1) Nil <*> (Cons (*2) Nil <*> Cons 1 (Cons 2 (Cons 3 Nil)))
e
pure (.) <*> Cons (+1) Nil <*> Cons (*2) Nil <*> Cons 1 (Cons 2 (Cons 3 Nil))
Entrambi dare lo stesso risultato, quindi perché la legge sulla composizione non finisce mai mi ha abbandonato. Potrebbe essere un problema con la libreria checkers?
Forse la dimensione degli elenchi che si finisce per generare è troppo grande? Cosa succede se si avvolgono i generatori con [ridimensiona] (http://hackage.haskell.org/package/QuickCheck-2.8.2/docs/Test-QuickCheck.html#v:resize), specificando una piccola dimensione? – danidiaz
Usando 'Elenco (Bool, Bool, Bool)' completato per me in circa 5 minuti. – ErikR
Se non ci sono soluzioni, accetterò semplicemente una risposta con un'istanza applicativa funzionante. –