una programacion hacer funciones estructuras estructura ejercicios dentro datos como ats anidadas anidada testing haskell data-structures quickcheck

testing - programacion - QuickCheck: instancias arbitrarias de estructuras de datos anidados que generan muestras equilibradas



programacion ats estructuras (3)

Como mencionó Janis, puede usar el paquete testing-feat , que crea enumeraciones de tipos de datos algebraicos arbitrarios. Esta es la forma más fácil de crear generadores imparciales distribuidos uniformemente para todos los árboles de hasta un tamaño determinado.

Así es como lo usarías para los rosales:

import Test.Feat (Enumerable(..), uniform, consts, funcurry) import Test.Feat.Class (Constructor) import Data.Tree (Tree(..)) import qualified Test.QuickCheck as QC -- We make an enumerable instance by listing all constructors -- for the type. In this case, we have one binary constructor: -- Node :: a -> [Tree a] -> Tree a instance Enumerable a => Enumerable (Tree a) where enumerate = consts [binary Node] where binary :: (a -> b -> c) -> Constructor c binary = unary . funcurry -- Now we use the Enumerable instance to create an Arbitrary -- instance with the help of the function: -- uniform :: Enumerable a => Int -> QC.Gen a instance Enumerable a => QC.Arbitrary (Tree a) where QC.arbitrary = QC.sized uniform -- QC.shrink = <some implementation>

La instancia de Enumerable también se puede generar automáticamente con TemplateHaskell:

deriveEnumerable ''''Tree

tl; dr: ¿cómo se escriben instancias de Arbitrary que no explotan si su tipo de datos permite demasiado anidamiento? ¿Y cómo garantizaría que estas instancias produzcan muestras verdaderamente aleatorias de su estructura de datos?

Quiero generar estructuras de árbol aleatorias, luego probar ciertas propiedades de estas estructuras después de que las he destruido con mi código de biblioteca. (NB: estoy escribiendo una implementación de un algoritmo de subtipificación, es decir, dada una jerarquía de tipos, el tipo A es un subtipo de tipo B. Esto puede hacerse arbitrariamente complejo, al incluir actualizaciones de herencia múltiple y posteriores a la inicialización en la jerarquía El método clásico que no admite ninguno de estos es la numeración de Schubert, y el último resultado que conozco es Alavi et al. 2008.)

Tomemos el ejemplo de los rosales, siguiendo a Data.Tree :

data Tree a = Node a (Forest a) type Forest a = [Tree a]

Una instancia muy simple (y no lo intentes en casa) de Arbitray sería:

instance (Arbitrary a) => Arbitrary (Tree a) where arbitrary = Node <$> arbitrary <$> arbitrary

Como ya tiene una instancia Arbitrary según la restricción de tipo, y el Forest tendrá una, porque [] es una instancia, esto parece sencillo. No terminará (típicamente) por razones muy obvias: dado que las listas que genera son arbitrariamente largas, las estructuras se vuelven demasiado grandes, y existe una buena posibilidad de que no quepan en la memoria. Incluso un enfoque más conservador:

arbitrary = Node <$> arbitrary <*> oneof [arbitrary,return []]

no funcionará, nuevamente, por la misma razón. Uno podría modificar el parámetro de tamaño para mantener baja la longitud de las listas, pero incluso eso no garantizará la finalización , ya que sigue siendo múltiples tiradas de dados consecutivas, y puede salir bastante mal (y quiero el nodo impar con 100 niños.)

Lo que significa que necesito limitar el tamaño de todo el árbol . Eso no es tan directo. unordered-containers lo tienen fácil: solo use fromList . Esto no es tan fácil aquí: ¿cómo se convierte una lista en un árbol, aleatoriamente, y sin incurrir en sesgos de una manera u otra (es decir, no favorecer ramas izquierdas, o árboles que son muy izquierdistas).

Algún tipo de construcción de amplitud (las funciones proporcionadas por Data.Tree son todas preordenar) de listas sería increíble, y creo que podría escribir una, pero resultaría no trivial. Ya que estoy usando árboles ahora, pero usaré cosas aún más complejas más adelante, pensé que podría tratar de encontrar una solución más general y menos compleja. ¿Hay alguno o tendré que recurrir a escribir mi propio generador Arbitrary no trivial? En este último caso, podría simplemente recurrir a pruebas unitarias, ya que esto parece demasiado trabajo.


Es posible que desee utilizar la biblioteca presentada en el documento "Feat: Enumeration funcional de tipos algebraicos" en el simposio Haskell 2012. Está en Hackage como prueba-feat, y un video de la charla que lo presenta está disponible aquí: http://www.youtube.com/watch?v=HbX7pxYXsHg


Utilice el sized :

instance Arbitrary a => Arbitrary (Tree a) where arbitrary = sized arbTree arbTree :: Arbitrary a => Int -> Gen (Tree a) arbTree 0 = do a <- arbitrary return $ Node a [] arbTree n = do (Positive m) <- arbitrary let n'' = n `div` (m + 1) f <- replicateM m (arbTree n'') a <- arbitrary return $ Node a f

(Adaptado de la presentación QuickCheck ).

PS Quizás esto genere árboles excesivamente equilibrados ...