2011-11-29 20 views
21

Typeclassopedia dice:.Haskell Functor ley implícita

"Un argumento similar muestra también que cualquier instancia Functor que satisface la primera ley (id fmap = id) satisfará automáticamente la segunda ley, así Prácticamente, esto significa que sólo el se debe verificar la primera ley (generalmente mediante una inducción muy directa) para garantizar que una instancia de Functor sea válida ".

Si este es el caso, ¿por qué mencionamos siquiera la segunda ley de funtores?

Law 1: fmap id = id 
Law 2: fmap (g . h) = (fmap g) . (fmap h) 

Respuesta

19

Mientras No puedo dar una prueba, creo que lo que está diciendo es que debido a parametricity, el sistema de tipo impone la segunda ley, siempre que la primera ley sea válida. La razón para especificar ambas reglas es que en la configuración matemática más general, puede tener alguna categoría C donde es perfectamente posible definir un "mapeo" desde C a sí mismo (es decir, un par de funciones endofunctions en Obj (C) y Hom (C) respectivamente) que obedece a la primera regla, pero no obedece la segunda regla, y por lo tanto deja de constituir un funtor.

Recuerde que Functor s en Haskell son endofunctors en la categoría Hask, y ni siquiera todo lo que matemáticamente se considera un endofunctor en Hask puede expresarse en Haskell ... las limitaciones de la regla de polimorfismo paramétrico a cabo siendo capaz de especificar un functor que no se comporta de manera uniforme para todos los objetos (tipos) que mapea.

Basado en this thread, el consenso general parece ser que la segunda ley se sigue de la primera para las instancias de Haskell Functor.Edward Kmett says,

Dadofmap id = id, fmap (f . g) = fmap f . fmap gse deduce del teorema para libre fmap.

Esto fue publicado como un aparte en un documento hace mucho tiempo, pero se me olvida dónde.

+1

Aquí hay una descripción más detallada para pasar del teorema libre a la segunda ley de Fnuctor, https://github.com/quchen/articles/blob/master/second_functor_law.md – David

+0

@David Hay un error tipográfico : "Fnuctor" -> "Functor" – fans656

3

Yo diría que la segunda ley no se menciona por razones de validez, sino más bien como una importante propiedad:

La primera ley dice que el mapeo de la función identidad sobre cada artículo en un recipiente no tiene efecto. El segundo dice que el mapeo de una composición de dos funciones sobre cada elemento en un contenedor es el igual que la primera asignación de una función, y luego mapeo de la otra. --- Typeclassopedia

(no puedo ver por qué esta primera ley implica la segunda ley, pero no soy un experto Haskeller - es probablemente evidente cuando se sabe lo que está pasando)

+0

No seas tan duro contigo mismo, no es tan obvio como todo eso. –

2
Se

Parece que se realizó quite recently que la ley 2 se sigue de la ley 1. Por lo tanto, cuando la documentación se escribió originalmente, probablemente se pensó que era un requisito independiente.

(Personalmente, no estoy convencido por el argumento, pero ya que no he tenido el tiempo para trabajar en los detalles mí mismo, me estoy dando el beneficio de la duda aquí.)

+0

El enlace que proporcionó parece ser sobre la singularidad de las instancias 'Functor' en lugar de la primera ley que implica la segunda ... [este hilo] (http://www.haskell.org/pipermail/haskell-cafe/2010- January/thread.html # 71631) es sobre esto último. –

+0

Ups, probablemente tienes razón. Pero el punto es :) – ibid

12

Usando seq, podemos escribir una instancia que satisface la primera regla, pero no el segundo.

data Foo a = Foo a 
    deriving Show 

instance Functor Foo where 
    fmap f (Foo x) = f `seq` Foo (f x) 

Podemos comprobar que esto satisface la primera ley:

fmap id (Foo x) 
= id `seq` Foo (id x) 
= Foo (id x) 
= Foo x 

Sin embargo, se rompe la segunda ley:

> fmap (const 42 . undefined) $ Foo 3 
Foo 42 
> fmap (const 42) . fmap undefined $ Foo 3 
*** Exception: Prelude.undefined 

Dicho esto, por lo general ignoran tales casos patológicos.

+1

Tenga en cuenta que cuando discrimina con seq entre diferentes comportamientos cuando se trata de valores inferiores, está "descifrando" el sistema de tipos. Los tipos haskell forman la categoría Hask, con funciones que son morfismos, _si_ no incluye fondos. Si incluye fondos en la imagen, una manipulación similar a la suya muestra que la estructura resultante no es una categoría (la asociatividad falla) por lo que no tiene sentido hablar de funtores tampoco – gigabytes