Pregunta

Quiero crear mi propia mónada. Esto es lo que escribió:

data LeafConType a = LeafCon (a,Int,Int)

instance Monad (LeafConType ) where
return = LeafCon 
lc@(LeafCon (t,i,n)) >>= f = if i>=n
                                then lc
                                else f (t,i,n)

Sin embargo, este trabajo no haga. GHC dice:

leafcon.hs:26:1:
    Occurs check: cannot construct the infinite type: a = (a, Int, Int)
    When generalising the type(s) for `return'
    In the instance declaration for `Monad LeafConType'

leafcon.hs:27:1:
    Occurs check: cannot construct the infinite type: a = (a, Int, Int)
    When generalising the type(s) for `>>='
    In the instance declaration for `Monad LeafConType'

¿Cuál es incorrecto con eso?


Quiero hacer cálculos, mientras que i es menor que n. n deben ser constantes por que aún no saben cómo hacer esto correctamente. Debe haber alguna combinación de Estado y lo mejor. Si usted tiene algunos consejos sentir a compartirlo conmigo libre: P

¿Fue útil?

Solución

Acerca return:

Prelude> :t return
return :: (Monad m) => a -> m a 

Así return toma un argumento de tipo a, y vuelve algo del tipo m a. En este caso es m LeafConType, por lo que se devuelve LeafConType a.

Ahora supongamos que pasamos True. Entonces a = Bool, por lo que el tipo de retorno debe ser LeafConType Bool. Sin embargo, se define:

return = LeafCon

Por lo tanto, se convierte en return True LeafCon True. Pero esto no está permitido, ya que la definición de tipo de estados que LeafConType

data LeafConType a = LeafCon (a, Int, Int)

Así que para LeafConType Bool el argumento a LeafCon debe tener un tipo (Bool, Int, Int), no sólo Bool. Y eso es lo que significa el error de compilación: a no pueden ser los mismos que (a, Int, Int). Usted Estado:

  

Quiero hacer cálculos mientras i es menor que n.

Esto significa que se necesitarán algunos valores por defecto para i y n, de lo contrario será imposible definir return. Si ambos son cero por defecto, entonces se podría definir:

return a = LeafCon (a, 0, 0)

Acerca (>>=):

Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

Ahora mira a su aplicación (notación ligeramente diferente, la misma idea):

lc@(LeafCon (t, i, n)) >>= f | i >= n    = lc 
                             | otherwise = f t

Lo que vemos aquí, es que se devuelve cuando lc i >= n. Pero lc es de tipo LeafConType a, mientras f es una función que puede devolver un valor de tipo LeafConType b, por cualquier b. Como resultado de ello podría ser que b no es igual a a y por lo tanto estos tipos no coinciden. En conclusión, en serio tiene que hacerse una pregunta:

¿Puede este tipo de cálculo puede expresar como una mónada de todos modos?

Otros consejos

Las funciones que ha indicado para >>= y return no satisfacen los tipos requerida por Monad:

return :: a -> LeafConType a

Teniendo en cuenta la declaración

return = LeafCon

le da la función del tipo incompatible

return :: (a, Int, Int) -> LeafConType a

Una declaración como return 42 por lo tanto, sería imposible en su mónada.

No entiendo lo que su mónada debe hacerlo en absoluto. En primer lugar echar un vistazo a simple, mónadas de trabajo!

instance Monad [] where
    (>>=) = concatMap
    return a = [a]

instance Monad Maybe where
    return = Just
    (Just x) >>= f = f x
    Nothing >>= f = Nothing

A juzgar por su descripción de lo que usted quiere que su mónada hacer, creo que quiere algo un poco como esto:

data LeafConType a = LeafCon { runLeafCon' :: Int -> Int -> (Maybe a, Int, Int) }

runLeafCon :: Int -> Int -> LeafConType a -> Maybe a
runLeafCon i n lc = let (t, _, _) = runLeafCon' lc i n in t

getI :: LeafConType Int
getI = LeafCon $ \i n -> (Just i, i, n)

getN :: LeafConType Int
getN = LeafCon $ \i n -> (Just n, i, n)

setI :: Int -> LeafConType ()
setI i = LeafCon $ \_ n -> (Just (), i, n)

setN :: Int -> LeafConType ()
setN n = LeafCon $ \i _ -> (Just (), i, n)

instance Monad LeafConType where
    return t = LeafCon $ \i n -> if (i < n) 
                                 then (Just t, i, n) 
                                 else (Nothing, i, n)

    (LeafCon k) >>= f = 
        LeafCon $ \i n -> 
            let (t, i', n') = k i n
            in case t of
                 Nothing -> (Nothing, i', n')
                 (Just t') -> if (i' < n')
                              then runLeafCon' (f t') i' n'
                              else (Nothing, i, n)


example :: Int -> LeafConType ((), Int)
example x = do 
  i <- getI
  m <- setI (i + x)
  return (m, i + x)

Algunos ejemplos:

*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)

Me tiró esto junto con bastante rapidez, es bastante feo, y no he comprobado para ver si obedece a ninguna de las leyes de las mónadas, por lo que su uso bajo su propio riesgo! :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top