Mientras que sería útil que le dio la implementación de gen
, soy adivinando que es algo como esto:
gen :: a -> ([a] -> [a]) -> ([a] -> Bool) -> a
gen init next stop = loop [init]
where
loop xs | stop xs = head xs
| otherwise = loop (next xs)
La propiedad que desea probar es que next
Nunca se suministra un lista vacía . Un obstáculo para probar esto es que desea verificar un invariante de bucle interno dentro de gen
, por lo que debe estar disponible en en el exterior. Vamos a modificar gen
para devolver esta información:
genWitness :: a -> ([a] -> [a]) -> ([a] -> Bool) -> (a,[[a]])
genWitness init next stop = loop [init]
where
loop xs | stop xs = (head xs,[xs])
| otherwise = second (xs:) (loop (next xs))
Utilizamos second
de Control.Arrow. El original gen
es fácil de definir en términos de genWitness:
gen' :: a -> ([a] -> [a]) -> ([a] -> Bool) -> a
gen' init next stop = fst (genWitness init next stop)
Gracias a la evaluación perezosa esto no nos va a dar mucho de arriba. Volver a la propiedad! Para permitir que se muestren las funciones generadas desde QuickCheck, usamos el módulo Test.QuickCheck.Function. Si bien no es estrictamente necesario aquí, una buena costumbre es monomorfizar la propiedad: utilizamos listas de Int
s en lugar de permitir la restricción de monomorfismo convirtiéndolos en listas de unidades. Vamos ahora a afirmar la propiedad:
prop_gen :: Int -> (Fun [Int] [Int]) -> (Fun [Int] Bool) -> Bool
prop_gen init (Fun _ next) (Fun _ stop) =
let trace = snd (genWitness init next stop)
in all (not . null) trace
Vamos a tratar la ejecutarlo con QuickCheck:
ghci> quickCheck prop_gen
algo parece bucle ... Sí, por supuesto: si gen
bucles stop
en las listas desde next
nunca es True
!Veamos en lugar de tratar de mirar prefijos finitas del rastreo de entrada lugar:
prop_gen_prefix :: Int -> (Fun [Int] [Int]) -> (Fun [Int] Bool) -> Int -> Bool
prop_gen_prefix init (Fun _ next) (Fun _ stop) prefix_length =
let trace = snd (genWitness init next stop)
in all (not . null) (take prefix_length trace)
Ahora obtenemos rápidamente aa contraejemplo:
385
{_->[]}
{_->False}
2
La segunda función es el argumento next
, y si devuelve la lista vacía, , luego el bucle en gen
dará next
una lista vacía.
Espero que esto responda a esta pregunta y que le dé alguna información en cómo probar las funciones de orden superior con QuickCheck.
Aquí hay una propiedad relacionada: "Para cualquier entrada no vacía,' next' producirá una salida no vacía ". Es posible que le interese probar esto en su lugar, o además de, la propiedad que menciona. –
@JohnL ¡De hecho, sí! Pero eso es una propiedad de 'next', no' gen', y 'next' es de primer orden, así que sé cómo probarlo. –