Подтвердить что ты не робот

Haskell Functor подразумевает закон

Typeclassopedia говорит:

"Аналогичный аргумент также показывает, что любой экземпляр Functor, удовлетворяющий первому закону (fmap id = id), автоматически удовлетворяет второму закону. Практически это означает, что нужно проверять только первый закон (обычно простая индукция), чтобы убедиться, что экземпляр Functor действителен.

Если это так, то почему мы даже упоминаем второй закон функтора?

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

Ответ 1

Пока я не могу дать доказательства, я считаю, что это говорит о том, что из-за параметричности система типов применяет второй закон до тех пор, пока первый закон имеет место. Причина, по которой указывается оба правила, заключается в том, что в более общем математическом параметре вы можете иметь некоторую категорию C, где вполне возможно определить "сопоставление" от C к себе (т.е. пара endofunctions на Obj (C) и Hom ( C) соответственно), которая подчиняется первому правилу, но не подчиняется второму правилу и поэтому не может составлять функтор.

Помните, что Functor в Haskell являются endofunctors в категории Hask, и даже не все, что математически считалось бы endofunctor на Hask, может быть выражено в Haskell... ограничения параметрического полиморфизма исключают возможность указать функтор, который не ведет себя равномерно для всех объектов (типов), которые он отображает.

Основываясь на этой теме, общий консенсус, похоже, заключается в том, что второй закон следует из первого для экземпляров Haskell Functor. Эдвард Кемет говорит,

Учитывая fmap id = id, fmap (f . g) = fmap f . fmap g следует из свободного теорема для fmap.

Это долгое время было опубликовано в документе в стороне, но я забыл, где.

Ответ 2

Используя seq, мы можем написать экземпляр, который удовлетворяет первому правилу, но не второму.

data Foo a = Foo a
    deriving Show

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

Мы можем проверить, что это удовлетворяет первому закону:

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

Однако он нарушает второй закон:

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

Тем не менее, мы обычно игнорируем такие патологические случаи.

Ответ 3

Я бы сказал, что второй закон не упоминается по причинам действительности, а скорее как важное свойство:

Первый закон гласит, что отображение функции тождества по каждому элементу в контейнере не действует. Второй говорит, что отображение состав двух функций по каждому элементу в контейнере равен то же самое, что и первое отображение одной функции, а затем отображение другой. --- Typeclassopedia

(Я не понимаю, почему этот первый закон подразумевает второй закон, но я не квалифицированный Haskeller - его, вероятно, очевидно, когда вы знаете, что происходит)

Ответ 4

Похоже, что совсем недавно было реализовано , что закон 2 следует из закона 1. Таким образом, когда документация была изначально написана, это было, вероятно, считается независимым требованием.

(Лично я не убежден в аргументе, но поскольку у меня не было времени самим разобраться в деталях, я даю ему возможность усомниться здесь.)