¿Qué significa componer dos Funtores?
El ejercicio 5 de Haskell Typeclassopedia Sección 3.2 pide una prueba o contraejemplo sobre la declaración
La composición de dos Funtores es también un Funtor.
Al principio pensé que esto estaba hablando de componer los métodos fmap
definidos por dos instancias separadas de un Functor
, pero eso realmente no tiene sentido, ya que los tipos no coincidirían por lo que puedo decir. Para dos tipos f
y f'
, los tipos de fmap
serían ser fmap :: (a -> b) -> f a -> f b
y fmap :: (a -> b) -> f' a -> f' b
, y eso realmente no parece componible. Entonces, ¿qué significa componer dos Functors
?
4 answers
A Functor
da dos asignaciones: una en el nivel de tipos de asignación de tipos a tipos (esto es el x
en instance Functor x where
), y otra en el nivel de cálculo de asignación de funciones a funciones (esto es el x
en fmap = x
). Está pensando en componer el mapeo a nivel de término, pero debería estar pensando en componer el mapeo a nivel de tipo; por ejemplo, dado
newtype Compose f g x = Compose (f (g x))
Puedes escribir
instance (Functor f, Functor g) => Functor (Compose f g)
? Si no, ¿por qué no?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-30 12:56:25
De lo que se trata es de la composición de constructores de tipos como []
y Maybe
, no de la composición de funciones como fmap
. Así, por ejemplo, hay dos formas de componer []
y Maybe
:
newtype ListOfMabye a = ListOfMaybe [Maybe a]
newtype MaybeOfList a = MaybeOfList (Maybe [a])
La afirmación de que la composición de dos Functors
es un Functor
significa que hay una forma formulaica de escribir una instancia Functor
para estos tipos:
instance Functor ListOfMaybe where
fmap f (ListOfMaybe x) = ListOfMaybe (fmap (fmap f) x)
instance Functor MaybeOfList where
fmap f (MaybeOfList x) = MaybeOfList (fmap (fmap f) x)
De hecho, la plataforma Haskell viene con el módulo Data.Functor.Compose
eso te da un Compose
escribe que hace esto "gratis":
import Data.Functor.Compose
newtype Compose f g a = Compose { getCompose :: f (g a) }
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
Compose
es particularmente útil con la extensión GeneralizedNewtypeDeriving
:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype ListOfMaybe a = ListOfMaybe (Compose [] Maybe a)
-- Now we can derive Functor and Applicative instances based on those of Compose
deriving (Functor, Applicative)
Tenga en cuenta que la composición de dos Applicative
s es también un Applicative
. Por lo tanto, puesto que []
y Maybe
son Applicative
s, también lo son Compose [] Maybe
y ListOfMaybe
. Componer Applicative
s es una técnica realmente ordenada que se está volviendo cada vez más común en estos días, como una alternativa a los transformadores de mónadas para los casos en los que no se necesita toda la potencia de las mónadas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-22 20:04:16
Realmente ayuda pensar en la interpretación categórica aquí, un funtor F: C -> D
toma objetos (valores) y morfismos (funciones) a objetos y morfismos de una categoría C
a objetos y morfismos en una categoría D
.
Para un segundo funtor G : D -> E
la composición de funtores G . F : C -> E
está tomando el codominio de F
fmap
transformación para ser el dominio de la G
fmap
transformación. En Haskell esto se logra con un poco de newtype desenvolviendo.
import Data.Functor
newtype Comp f g a = Comp { unComp :: f (g a) }
compose :: f (g a) -> Comp f g a
compose = Comp
decompose :: Comp f g a -> f (g a)
decompose = unComp
instance (Functor f, Functor g) => Functor (Comp f g) where
fmap f = compose . fmap (fmap f) . decompose
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-04 18:58:34
La composición de dos funciones es cuando pones una función dentro de otra función, como
round (sqrt 23)
Esta es la composición de las dos funciones round
y sqrt
. Del mismo modo, la composición de dos funtores es cuando pones un funtor dentro de otro funtor, como
Just [3, 5, 6, 2]
List es un funtor, y quizás también lo es. Puede obtener alguna intuición de por qué su composición también es un funtor si intenta averiguar qué debería hacer fmap con el valor anterior. De por supuesto que debe mapear sobre el contenido del funtor interno!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-04 18:42:29