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?

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top