instancias Functor / Aplicativo para Estado en Haskell
-
30-09-2019 - |
Pregunta
Después de leer (y rozando algunas secciones de) papel de Wadler en mónadas, decidí trabajar a través del papel más de cerca, definiendo funtor y casos aplicativos para cada una de las mónadas que describe. Utilizando el tipo de sinónimos
type M a = State -> (a, State)
type State = Int
Wadler utiliza para definir la mónada estado, he lo siguiente (utilizando nombres relacionados para que pueda definirlos con una declaración newtype más adelante).
fmap' :: (a -> b) -> M a -> M b
fmap' f m = \st -> let (a, s) = m st in (f a, s)
pure' :: a -> M a
pure' a = \st -> (a, st)
(<@>) :: M (a -> b) -> M a -> M b
sf <@> sv = \st -> let (f, st1) = sf st
(a, st2) = sv st1
in (f a, st2)
return' :: a -> M a
return' a = pure' a
bind :: M a -> (a -> M b) -> M b
m `bind` f = \st -> let (a, st1) = m st
(b, st2) = f a st1
in (b, st2)
Cuando cambio al uso de un constructor de tipos en una declaración newtype, por ejemplo.,
newtype S a = S (State -> (a, State))
todo se desmorona. Todo es simplemente una ligera modificación, por ejemplo,
instance Functor S where
fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s))
instance Applicative S where
pure a = S (\st -> (a, st))
Sin embargo, nada se ejecuta en GHC debido al hecho de que la expresión lambda se oculta dentro de ese tipo constructor. Ahora, la única solución que veo es definir una función:
isntThisAnnoying s (S m) = m s
a fin de obligar a s 'st' y, de hecho devolver un valor, por ejemplo.,
fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s))
¿Hay otra manera de hacer esto que no utilice estas funciones auxiliares?
Solución
Si nos fijamos aquí , se verá que lo definen así:
newtype State s a = State { runState :: (s -> (a,s)) }
a fin de dar la lambda interior un nombre.
Otros consejos
La forma más habitual es definir newtype newtype S a = S {runState : State -> (a, State)}
. A continuación, en lugar de su isntThisAnnoying s (S m)
puede escribir runState t s
donde t
es la misma que S m
.
Usted tiene que utilizar un tipo newtype
porque sinónimos no pueden ser clase de tipos casos.