Estaba siguiendo el documento "Kleisli arrows of outrageous fortune" de Conor McBride y he publicado mi implementación de su código here. Brevemente, define los siguientes tipos y clases:Reingresando notación para mónadas indexadas
type a :-> b = forall i . a i -> b i
class IFunctor f where imap :: (a :-> b) -> (f a :-> f b)
class (IFunctor m) => IMonad m where
skip :: a :-> m a
bind :: (a :-> m b) -> (m a :-> m b)
data (a := i) j where
V :: a -> (a := i) i
Luego se define dos tipos de liga, el último de los cuales utiliza (:=)
para restringir el índice inicial:
-- Conor McBride's "demonic bind"
(?>=) :: (IMonad m) => m a i -> (a :-> m b) -> m b i
(?>=) = flip bind
-- Conor McBride's "angelic bind"
(>>=) :: (IMonad m) => m (a := j) i -> (a -> m b j) -> m b i
m >>= f = bind (\(V a) -> f a) m
Este último se unen funciona perfectamente bien para reconsolidación do
notación de usar mónadas indexadas con la extensión RebindableSyntax
, usando las siguientes definiciones correspondientes para return
y fail
:
return :: (IMonad m) => a -> m (a := i) i
return = skip . V
fail :: String -> m a i
fail = error
... pero el problema es que no puedo obtener el enlace anterior (es decir (?>=)
) para trabajar. He intentado en lugar definiendo (>>=)
y return
ser:
(>>=) :: (IMonad m) => m a i -> (a :-> m b) -> m b i
(>>=) = (?>=)
return :: (IMonad m) => a :-> m a
return = skip
Entonces creó un tipo de datos garantizada habitar un índice específico:
data Unit a where
Unit :: Unit()
Pero cuando intento volver a enlazar do
notación utilizando las nuevas definiciones para (>>=)
y return
, que no funciona, como se demuestra en el siguiente ejemplo:
-- Without do notation
test1 = skip Unit >>= \Unit -> skip Unit
-- With do notation
test2 = do
Unit <- skip Unit
skip Unit
test1
controles de tipo, pero no test2
, lo cual es raro, ya que pensamos que todo lo que hizo fue dejar que RebindableSyntax
do
notación desugar test2
a test1
, así que si test1
tipo comprobaciones, entonces ¿por qué no lo hace test2
? El error que consigo es:
Couldn't match expected type `t0 -> t1'
with actual type `a0 :-> m0 b0'
Expected type: m0 a0 i0 -> (t0 -> t1) -> m Unit()
Actual type: m0 a0 i0 -> (a0 :-> m0 b0) -> m0 b0 i0
In a stmt of a 'do' block: Unit <- skip Unit
In the expression:
do { Unit <- skip Unit;
skip Unit }
el error se mantiene incluso cuando se utiliza la sintaxis explícita forall
en lugar del operador :->
tipo.
Ahora, sé que hay otro problema con el uso del "enlace demoníaco", que es que no puede definir (>>)
, pero todavía quería ver qué tan lejos podía ir con él. ¿Alguien puede explicar por qué no puedo hacer que GHC deshaga el "lazo demoníaco", incluso cuando normalmente lo haría?
Dado que esto surgió en una [nueva pregunta duplicada] (http://stackoverflow.com/questions/33488322/ranknpolymorphism-and-kleisli-arrows-of-outrageous-fortune), señalaré que hoy en día GHC (actualmente 7.10.2) apenas admite 'ImpredicativeTypes' en absoluto, por lo tanto, mucho más que la notación' do 'se rompe para este código ahora. –