Question

Je veux créer ma propre monade. C'est ce que je l'ai écrit:

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)

Mais ce travail de Do not. GHC dit:

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'

Quel est le problème avec ça?


Je veux faire des calculs alors que i est inférieur à n. n doit être constantes par je ne sais pas encore comment faire correctement. Il devrait y avoir un mélange d'Etat et peut-être. Si vous avez des conseils ne hésitez pas à partager avec moi: P

Était-ce utile?

La solution

A propos de return:

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

return prend un argument de type a et renvoie quelque chose de type m a. Dans ce cas m est LeafConType, donc LeafConType a est retourné.

Supposons maintenant que nous passons True. Ensuite a = Bool, de sorte que le type de retour doit être LeafConType Bool. Cependant, vous définissez:

return = LeafCon

Alors, return True devient LeafCon True. Mais ce n'est pas autorisé, parce que la définition de type de LeafConType indique que

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

Donc, pour LeafConType Bool l'argument LeafCon doit avoir le type (Bool, Int, Int), pas seulement Bool. Et c'est-ce que l'erreur de compilation signifie: a ne peut pas être le même que (a, Int, Int). Vous déclarez:

  

Je veux faire des calculs en i est inférieure à n.

Cela signifie que vous aurez besoin de quelques valeurs par défaut pour i et n, car autrement il sera impossible de définir return. Si les deux d'entre eux sont zéro par défaut, vous pouvez alors définir:

return a = LeafCon (a, 0, 0)

A propos de (>>=):

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

Maintenant, regardez votre implémentation (notation légèrement différente, même idée):

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

Ce que nous voyons ici, est que lc est retourné lorsque i >= n. Mais lc est de type LeafConType a, alors que f est une fonction qui peut renvoyer une valeur de type LeafConType b, pour any b. Par conséquent, il se pourrait que b ne correspond pas à a et par conséquent, ces types ne correspondent pas. En conclusion, vous avez sérieusement vous poser une question:

Peut ce type de calcul exprimé comme une monade de toute façon?

Autres conseils

Les fonctions que vous avez spécifié pour >>= et return ne satisfont pas les types requis par Monad:

return :: a -> LeafConType a

Compte tenu de la déclaration

return = LeafCon

vous donnez la fonction du type incompatible

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

Une déclaration comme return 42 serait donc impossible dans votre monade.

Je ne comprends pas ce que votre monade devrait faire du tout. Tout d'abord jeter un oeil à simple, monades travail!

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

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

A en juger par votre description de ce que vous voulez que votre monade faire, je pense que vous voulez quelque chose un peu comme ceci:

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)

Voici quelques exemples:

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

Je jeté cela ensemble assez rapidement, il est assez laid, et je n'ai pas vérifié pour voir si elle obéit à l'une des lois Monad, utilisez donc à vos risques et périls! :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top