Haskell Functor implied law

后端 未结 4 1225
清酒与你
清酒与你 2021-02-07 02:49

Typeclassopedia says:

\"A similar argument also shows that any Functor instance satisfying the first law (fmap id = id) will automatically satisfy the second law as well

相关标签:
4条回答
  • 2021-02-07 03:18

    I'd say the second law is not mentioned for validity reasons, but rather as an important property:

    The first law says that mapping the identity function over every item in a container has no effect. The second says that mapping a composition of two functions over every item in a container is the same as first mapping one function, and then mapping the other. --- Typeclassopedia

    (I can't see why this first law implies the second law, but I'm not a skilled Haskeller - its probably obvious when you know what's going on)

    0 讨论(0)
  • 2021-02-07 03:20

    While I can't give a proof, I believe what this is saying is that due to parametricity, the type system enforces the second law as long as the first law holds. The reason to specify both rules is that in the more general mathematical setting, you might have some category C where it is perfectly possible to define a "mapping" from C to itself (i.e. a pair of endofunctions on Obj(C) and Hom(C) respectively) which obeys the first rule but fails to obey the second rule, and therefore fails to constitute a functor.

    Remember that Functors in Haskell are endofunctors on the category Hask, and not even everything that would mathematically be considered an endofunctor on Hask can be expressed in Haskell... the constraints of parametric polymorphism rule out being able to specify a functor which does not behave uniformly for all objects (types) which it maps.

    Based on this thread, the general consensus seems to be that the second law follows from the first for Haskell Functor instances. Edward Kmett says,

    Given fmap id = id, fmap (f . g) = fmap f . fmap g follows from the free theorem for fmap.

    This was published as an aside in a paper a long time back, but I forget where.

    0 讨论(0)
  • 2021-02-07 03:28

    Using seq, we can write an instance which satisfies the first rule but not the second one.

    data Foo a = Foo a
        deriving Show
    
    instance Functor Foo where
        fmap f (Foo x) = f `seq` Foo (f x)
    

    We can verify that this satisfies the first law:

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

    However, it breaks the second law:

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

    That said, we usually ignore such pathological cases.

    0 讨论(0)
  • 2021-02-07 03:33

    It seems that it was realized quite recently that law 2 follows from law 1. Thus, when the documentation was originally written, it was probably thought to be an independent requirement.

    (Personally, I'm not convinced by the argument, but since I haven't had the time to work out the details myself, I'm giving it the benefit of doubt here.)

    0 讨论(0)
提交回复
热议问题