Потребность в чистом в аппликативах - PullRequest
19 голосов
/ 18 февраля 2020

Я изучаю Haskell. Мне кажется (я, вероятно, ошибаюсь), что функция pure на самом деле не нужна, например:

pure (+) <*> [1,2,3] <*> [3,4,5]

можно записать как

(+) <$> [1,2,3] <*> [3,4,5]

Может кто-нибудь объяснить преимущество, которое обеспечивает функция pure по сравнению с явным отображением с fmap?

Ответы [ 2 ]

20 голосов
/ 18 февраля 2020

fmap не всегда сокращает это. В частности, pure - это то, что позволяет вам ввести f (где f - Applicative), когда у вас его еще нет. Хорошим примером является

sequence :: Applicative f => [f a] -> f [a]

. Он берет список «действий», производящих значения, и превращает его в действие, создающее список значений. Что происходит, когда в списке нет действий? Единственный вменяемый результат - это действие, которое не дает никаких значений:

sequence [] = pure [] -- no way to express this with an fmap
-- for completeness
sequence ((:) x xs) = (:) <$> x <*> sequence xs

Если у вас не было pure, вам пришлось бы требовать непустого списка действий. Вы можете определенно заставить его работать, но это все равно, что говорить о сложении без упоминания 0 или умножения без 1 (как говорили другие, потому что Applicative s моноидальны). Вы будете неоднократно сталкиваться с крайними случаями, которые могут быть легко решены с помощью pure, но вместо этого должны быть решены странными ограничениями на ваши входы и другие вспомогательные средства.

8 голосов
/ 18 февраля 2020

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

Могут быть практические причины для включения pure в классе типов, но многие абстракции Haskell получены из теоретических основ, и я считаю, что это относится и к Applicative. Как говорится в документации, это сильный слабый моноидальный функтор (подробности см. https://cstheory.stackexchange.com/q/12412/56098). Я предполагаю, что pure служит тождеством , точно так же, как return делает для Monad (который является моноидом в категории эндофункторов ).

Рассмотрим pure и liftA2:

pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c

Если вы немного косите, вы можете себе представить, что liftA2 - это бинарная операция, что также указано в документации:

Поднимите бинарную функцию в действия.

pure, то есть соответствующий тождество.

...