programmers for haskell theory functor

haskell - for - category theory pdf



¿Qué significa componer dos Functors? (4)

El ejercicio 5 de Haskell Typeclassopedia Sección 3.2 solicita una prueba o un contraejemplo en la declaración

La composición de dos Functors es también un Functor.

Al principio pensé que se trataba de componer los métodos fmap definidos por dos instancias distintas de un Functor , pero eso no tiene sentido, ya que los tipos no coincidirían tanto como puedo decir. Para dos tipos f y f'' , los tipos de fmap serían fmap :: (a -> b) -> fa -> fb y fmap :: (a -> b) -> f'' a -> f'' b , Y eso realmente no parece composable. Entonces, ¿qué significa componer dos Functors ?


De lo que se habla es de la composición de constructores de tipos como [] y Maybe , no de la composición de funciones como fmap . Entonces, 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 específica de escribir una instancia de 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 que le proporciona un tipo de Data.Functor.Compose que lo hace "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 es también un Applicative . Por lo tanto, dado que [] y Maybe are Applicative s, también lo son Compose [] Maybe y ListOfMaybe . La composición de Applicative s es una técnica realmente pulcra que se está volviendo cada vez más común en estos días, como alternativa a los transformadores de mónada para los casos en los que no se necesita todo el poder de las mónadas.


La composición de dos funciones es cuando se coloca una función dentro de otra función, como

round (sqrt 23)

Esta es la composición de las dos funciones round y sqrt . De manera similar, la composición de dos funtores es cuando se coloca un funtor dentro de otro funtor, como

Just [3, 5, 6, 2]

La lista es un functor, y también lo es Maybe. Puede obtener alguna intuición de por qué su composición también es un functor si intenta averiguar qué debería hacer fmap con el valor anterior. ¡Por supuesto que debe mapearse sobre el contenido del functor interno!


Realmente ayuda pensar acerca de la interpretación categórica aquí, un functor F: C -> D lleva 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 functor G : D -> E la composición de los funtores G . F : C -> E G . F : C -> E simplemente toma el codominio de la transformación F fmap como el dominio de la transformación G fmap . En Haskell esto se logra con un pequeño tipo de desenvolvimiento.

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


Un Functor proporciona dos asignaciones: una en el nivel de tipo, tipos de mapeo a tipos (este es el x en la instance Functor x where ), y uno en el nivel de cálculo, funciones de mapeo a las funciones (este es el x en fmap = x ). Está pensando en componer el mapeo a nivel de término, pero debería pensar 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, porque no?