Puede liftM difieren de liftA?
-
06-07-2019 - |
Pregunta
De acuerdo a el Typeclassopedia (entre otras fuentes), Applicative
lógicamente pertenece entre Monad
y Pointed
(y por lo tanto Functor
) en el tipo de la jerarquía de clases, así que lo ideal sería tener algo como esto si la Haskell preludio fueron escritas el día de hoy:
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Pointed f where
pure :: a -> f a
class Pointed f => Applicative f where
(<*>) :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
-- either the traditional bind operation
(>>=) :: (m a) -> (a -> m b) -> m b
-- or the join operation, which together with fmap is enough
join :: m (m a) -> m a
-- or both with mutual default definitions
f >>= x = join ((fmap f) x)
join x = x >>= id
-- with return replaced by the inherited pure
-- ignoring fail for the purposes of discussion
(Donde los valores predeterminados fueron re-escritas por mí a partir de la explicación en Wikipedia, los errores de ser mi propia cuenta, pero si hay errores es al menos posible en principio.)
Como las bibliotecas están definidos actualmente, tenemos:
liftA :: (Applicative f) => (a -> b) -> f a -> f b
liftM :: (Monad m) => (a -> b) -> m a -> m b
y:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
ap :: (Monad m) => m (a -> b) -> m a -> m b
Observe la similitud entre estos tipos dentro de cada par.
Mi pregunta es:son liftM
(distintos de liftA
) y ap
(distintos de <*>
), simplemente un resultado de la realidad histórica que Monad
no fue diseñado con Pointed
y Applicative
en la mente?O que en alguna otra forma de comportamiento (potencialmente, para algunas legal Monad
definiciones distintas de las versiones que sólo requiere de un Applicative
contexto?
Si son distintas, podría dar un simple conjunto de definiciones (obedecer las leyes necesarias de Monad
, Applicative
, Pointed
, y Functor
las definiciones descritas en el Typeclassopedia y en otros lugares, pero no se aplica por el tipo de sistema) para que liftA
y liftM
se comportan de manera diferente?
Alternativamente, si no son distintos, podría usted demostrar su equivalencia con esas mismas leyes locales?
Solución
liftA
, liftM
, fmap
, y .
debe ser todos la misma función, y que debe si cumplen el functor de la ley:
fmap id = id
Sin embargo, esto no es verificada por Haskell.
Ahora para el Aplicativo.Es posible que ap
y <*>
ser distinto para algunos functors simplemente porque no podía ser más que una aplicación que satisface los tipos y las leyes.Por ejemplo, la Lista tiene más de un posible Applicative
ejemplo.Usted podría declarar un aplicativo de la siguiente manera:
instance Applicative [] where
(f:fs) <*> (x:xs) = f x : fs <*> xs
_ <*> _ = []
pure = repeat
El ap
la función sería aún se define como liftM2 id
, que es el Applicative
instancia que viene de forma gratuita con cada Monad
.Pero aquí tienes un ejemplo de un tipo de constructor de tener más de uno Applicative
instancia, ambos de los cuales cumplir las leyes.Pero si su mónadas y su aplicativo functors en desacuerdo, se considera una buena forma de tener diferentes tipos de ellos.Por ejemplo, la Applicative
la instancia anterior no está de acuerdo con la mónada para []
, por lo que realmente debería decir newtype ZipList a = ZipList [a]
y, a continuación, hacer que la nueva instancia para ZipList
en lugar de []
.
Otros consejos
Ellos pueden diferir, pero no deberían .
Pueden diferir porque pueden tener implementaciones diferentes: una se define en un instance Applicative
mientras que la otra se define en un instance Monad
. Pero si realmente difieren, entonces diría que el programador que escribió esas instancias escribió un código engañoso.
Tienes razón: las funciones existen como existen por razones históricas. La gente tiene fuertes ideas sobre cómo deberían haber sido las cosas.