Tipo di errore durante il tentativo di implementare la funzione (>> =) al fine di creare un trasformatore monade personalizzato
-
27-09-2019 - |
Domanda
Sto cercando di creare un trasformatore monade per un progetto futuro, ma purtroppo, il mio attuazione di Monade typeclasse (>> =) funzione non è attiva.
Prima di tutto, qui è l'implementazione del monade sottostante:
newtype Runtime a = R {
unR :: State EInfo a
} deriving (Monad)
Qui, l'attuazione della Monade typeclasse viene fatto automaticamente dal GHC (utilizzando il linguaggio pragma GeneralizedNewtypeDeriving
).
La monade trasformatore è definito come:
newtype RuntimeT m a = RuntimeT {
runRuntimeT :: m (Runtime a)
}
Il problema deriva dal modo in cui ho instanciate la funzione (>> =) del typeclasse Monade:
instance (Monad m) => Monad (RuntimeT m) where
return a = RuntimeT $ (return . return) a
x >>= f = runRuntimeT x >>= id >>= f
Il mio modo di vedere, le prime corse >>=
nella monade m
sottostante. Così, runRuntimeT x >>=
restituisce un valore di tipo Runtime a
(giusto?). Poi, il codice seguente, id >>=
, dovrebbe restituire un valore di tipo a
. Questo valore è il trasmesso alla funzione f di tipo f :: (Monad m) => a -> RuntimeT m b
.
E qui viene il problema Tipo: il tipo di funzione di f
non corrisponde al tipo richiesto dalla funzione (>> =). Jow posso fare questo coerente? Posso capire perché questo non funziona, ma non riesco a trasformarlo in qualcosa di functionnal.
Modifica: Il messaggio di errore:
Core.hs:34:4:
Occurs check: cannot construct the infinite type: m = RuntimeT m
When generalising the type(s) for `>>='
In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.
Grazie per aiuto, e non esitate a correggere eventuali difetti nel mio messaggio,
Charlie P.
Soluzione
Per riallacciarmi a ciò che ha detto Reid Barton su StateT
- ecco come si potrebbe definire RuntimeT
utilizzando StateT
. La monade Runtime
può essere banalmente definita utilizzando la monade identità.
newtype RuntimeT m a = R {
unR :: StateT EInfo m a
}
type Runtime = RuntimeT Identity
instance Monad m => Monad (RuntimeT m) where
return = R . return
(R m) >>= f = R (m >>= unR . f)
Altri suggerimenti
Il solito StateT s m
monade manda a
a s -> m (a, s)
ma si sta lavorando con m (s -> (a, s))
invece. Non credo che queste ultime forme una monade per s
generale. Sei sicuro che non vuoi solo usare StateT
?
Ecco il motivo per cui non credo a
→ m (s -> (a, s))
è una monade: Per >>=
scrivere ho bisogno di una funzione che prende argomenti di tipi
m (s -> (a, s))
a -> m (s -> (b, s))
e restituisce un valore di tipo
m (s -> (b, s))
Gli "effetti" (cioè fmap (const ())
) del risultato deve essere quelle del primo argomento, poiché abbiamo modo per ottenere un a
per passare al secondo argomento. Dal momento che appare m
solo sulla parte esterna del tipo di risultato, abbiamo poi non si può utilizzare il secondo argomento per niente-non ci sarà alcun modo per sbarazzarsi del m
introduce.