2010-09-22 17 views
5

Im bastante nuevo para Haskell. tengo un tipo de datos:Haskell Aleatorio de tipo de datos

data Sentence= Prop Int 
      | No Sentence 
      | And [Sentence] 
      | Or [Sentence] 
      deriving Eq 

que ya escribió un Show de instancia para que

Sin embargo, si tiene sentido o no, me gustaría ser capaz de generar una frase al azar. ¿Cómo puedo lograr esto en Haskell?

Respuesta

5

La generación aleatoria de números es un ejemplo típico de una operación "impura", ya que llamar a un generador aleatorio dos veces producirá resultados diferentes: la naturaleza de Haskell no lo permite.

Por lo tanto, es necesario utilizar un llamado mónada Gen a que representa un generador aleatorio , que, cuando se ejecuta, se obtiene un valor de tipo a.

Afortunadamente, puede combinar estos generadores en una sintaxis bastante bien ...

lo tanto, sólo necesita un poco de library que implementa un generador de este tipo - y aquí vamos.

randomNo = No <$> randomSentence 
randomProp = Prop <$> choose (1, 10) 
[...] 

randomSentence = oneOf [randomNo, randomProp, ...] 
+0

Gracias por la respuesta ultrarrápida, pero ¿qué quiere decir con <$>? – SirLenz0rlot

+1

Ah, es de 'Control.Applicative', solo una sintaxis simplificada que significa que puede aplicar una función a un valor aleatorio. – Dario

+5

Es simplemente 'fmap' – fuz

1

La forma más sencilla es utilizar el módulo de System.Random, está en el paquete al azar, por lo que probablemente tenga que instalar primero.

Este módulo define a las clases de tipos:

class RandomGen g where 
    next :: g -> (Int,g) 
    -- ... 

class Random r where 
    random :: RandomGen g => g -> (a,g) 
    randomR :: RandomGen g => (r,r) -> g -> (a, g) 

La clase de tipos, hay que aplicar es al azar, específica la primera función (como el segundo no tiene sentido, sólo se puede aplicar como randomR = const random ¿Qué random.? se obtiene un generador aleatorio como entrada, tiene que generar lo que necesita para ello, y dar al nuevo generador

para generar los valores aleatorios, se podría utilizar la mónada State, o algo como esto:.

random g = (myResult,gn) where 
    (random1,g1) = next g 
    (random2,g2) = next g2 
    -- ... 

continuación, puede utilizar los sistemas de generador aleatorio por esta función:

randomIO :: Random r => IO r 

Se está predefinido y se obtiene un valor diferente cada llamada.

Sin embargo, finalmente tiene que decidir cómo definir su instancia aleatoria.

5

Mi método favorito es utilizar el paquete MonadRandom. Aunque se reduce a lo mismo que pasar un poco de RandomGen, lo hace por usted y se asegura de que no se equivoque en el proceso (como pasar un generador ya usado). Además, Rand StdGen a tiene la interpretación agradable de "una distribución de probabilidad de a s".

Para su ejemplo, podría tener este aspecto:

-- a type for probability distributions 
type Dist = Rand StdGen 

-- pick uniformly between a list of values 
uniform :: [a] -> Dist a 
uniform xs = do 
    ix <- getRandomR (0, length xs - 1) 
    return (xs !! ix) 

-- return a list of elements generated by the given distribution 
randList :: Int -> Dist a -> Dist [a] 
randList maxElems dist = do 
    elems <- getRandomR (0, maxElems) 
    sequence (replicate elems dist) 

-- return a probability distribution of sentences 
randSentence :: Dist Sentence 
randSentence = do 
    -- choose one of these four distributions by a uniform distribution 
    -- (uniform [...] returns a distribution of distributions) 
    dist <- uniform [ 
     Prop <$> getRandom, 
     No <$> randSentence, 
     And <$> randList 5 randSentence, 
     Or <$> randList 5 randSentence ] 
    -- and sample the one we chose 
    dist 

Nota el número mágico 5 hasta allí. Eso es para que no obtengamos 2 mil millones de listas de elementos. Es posible que desee ajustar la distribución de la cantidad de términos en sus listas generadas al azar.

Y para ejecutarlo puede utilizar evalRandIO o muchas otras cosas, como dicen:

main = print =<< evalRandIO randSentence 
+1

Gracias! Encontré que la biblioteca Monad.Random no está incluida en el último paquete de Windows. tal vez por una razón? Desde que copié y pegué su fuente (http://www.haskell.org/haskellwiki/NewMonads/MonadRandom) en un archivo propio, me da errores de los cuales no tengo ni idea de cómo resolverlo: declaración de instancia ilegal para 'MonadState s (RandT gm) ' – SirLenz0rlot

+1

Debe instalar a través de cabal, no copiar y pegar. Supongo que tiene instalada la plataforma Haskell. Luego ejecútese 'cabal instalar MonadRandom' en el símbolo del sistema. Es posible que tengas que "actualizar cabal" primero. – luqui

1
pick :: [a] -> IO a 
pick xs = randomRIO (0, length xs - 1) >>= return . (xs !!) 

Ejecutar la selección sobre cualquier lista.

Cuestiones relacionadas