Creazione di monadi a Haskell
Domanda
Voglio creare la mia monade. Questo è ciò che ho scritto:
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)
Ma questo lavoro Dont. 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'
Cosa c'è di sbagliato in questo?
che voglio fare calcoli, mentre i è inferiore a n. n dovrebbe essere costanti per non so ancora come fare questo corretto. Dovrebbe essere un po 'di mix di Stato e di darsi. Se si dispone di alcuni consigli non esitate a condividere con me: P
Soluzione
Informazioni su return
:
Prelude> :t return
return :: (Monad m) => a -> m a
Quindi return
prende un argomento di tipo a
, e restituisce qualcosa di tipo m a
. In questo caso è m
LeafConType
, così LeafConType a
viene restituito.
Ora supponiamo che passiamo True
. Poi a = Bool
, in modo che il tipo di ritorno deve essere LeafConType Bool
. Tuttavia, si definisce:
return = LeafCon
Quindi, return True
diventa LeafCon True
. Ma questo non è consentito, in quanto la definizione del tipo di LeafConType
afferma che
data LeafConType a = LeafCon (a, Int, Int)
Quindi, per LeafConType Bool
l'argomento LeafCon
deve avere tipo (Bool, Int, Int)
, non solo Bool
. E questo è ciò che significa l'errore di compilazione: a
non può essere lo stesso di (a, Int, Int)
. Lei afferma:
che voglio fare calcoli mentre
i
è inferioren
.
Questo significa che avrete bisogno di alcuni valori predefiniti per i
e n
, altrimenti sarà impossibile da definire return
. Se entrambi sono pari a zero per default, allora si potrebbe definire:
return a = LeafCon (a, 0, 0)
Informazioni su (>>=)
:
Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
Ora guardate l'implementazione (notazione leggermente diversa, stessa idea):
lc@(LeafCon (t, i, n)) >>= f | i >= n = lc
| otherwise = f t
Quello che vediamo qui, è che lc
viene restituito quando i >= n
. Ma lc
è di tipo LeafConType a
, mentre f
è una funzione che può restituire un valore di tipo LeafConType b
, per qualsiasi b
. Come risultato potrebbe essere che b
non è uguale a a
e quindi questi tipi non corrispondono. In conclusione, si deve seriamente porsi una domanda:
Può questo tipo di calcolo essere espresso come una monade in ogni caso?
Altri suggerimenti
Le funzioni specificati per >>=
e return
non soddisfano le tipologie richieste dal Monad
:
return :: a -> LeafConType a
Data la dichiarazione
return = LeafCon
si dà la funzione del tipo incompatibile
return :: (a, Int, Int) -> LeafConType a
Una dichiarazione come return 42
sarebbe quindi impossibile nel vostro monade.
Non capisco che cosa il vostro monade dovrebbe fare a tutti. In primo luogo dare un'occhiata a semplici, monadi di lavoro!
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
A giudicare dalla tua descrizione di ciò che si desidera che il monade da fare, penso che si desidera qualcosa di un po 'come questo:
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)
Alcuni esempi:
*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)
ho buttato questo insieme abbastanza rapidamente, è piuttosto brutto, e non ho controllato per vedere se si obbedisce una delle leggi Monade, in modo da utilizzare a vostro rischio e pericolo! :)