A necessidade de puro em candidatos

19

Estou aprendendo os candidatos de Haskell. Parece-me (provavelmente estou errado) que a purefunção não é realmente necessária, por exemplo:

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

pode ser escrito como

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

Alguém pode explicar o benefício que a purefunção fornece sobre o mapeamento explícito fmap?

Gil Shafriri
fonte
11
Você está correto - pure f <*> xé exatamente o mesmo que fmap f x. Estou certo de que há alguma razão pela qual purefoi incluído Applicative, mas não sei por que.
bradrn 18/02
4
Não tenho tempo para uma resposta e não estou convencido de que isso daria uma resposta boa ou completa, mas uma observação: purepermite usar, bem, valores "puros" em uma computação Aplicativa. Enquanto, como você observa corretamente, pure f <*> xé o mesmo que f <$> x, não existe um equivalente para, digamos f <*> x <*> pure y <*> z,. (Pelo menos acho que não.)
Robin Zigmond
3
Como outra justificativa mais teórica - existe uma formulação alternativa que a relaciona de perto com a Monoidclasse importante - na qual purecorresponde ao Monoidelemento de identidade de. (Isso sugere que Applicativesem purepoderia ser interessante, pois Semigroup- que é um Monoidsem necessariamente ter uma identidade - ainda é usado. Na verdade, agora penso nisso, me lembro que o PureScript tem exatamente uma pureclasse "Aplicativa sem ", embora eu não não sei para que serve.)
Robin Zigmond
2
@RobinZigmond fmap (\f' x' z' -> f' x' y z') f <*> x <*> z, eu acho. A idéia está na Applicativedocumentação como a lei do "intercâmbio".
HTNW
3
@RobinZigmond Applicativesem pureexiste a partir Applyde semigroupóides .
duplode 18/02

Respostas:

8

Estou no limite da minha competência aqui, por isso não aceite isso por mais do que é, mas demorou um pouco demais para comentar.

Pode haver razões práticas para incluir purena classe type, mas muitas abstrações de Haskell são derivadas de fundamentos teóricos, e acredito que esse seja o caso Applicativetambém. Como a documentação diz, é um forte functor monoidal relaxado (consulte https://cstheory.stackexchange.com/q/12412/56098 para obter uma elaboração). Suponho que isso puresirva como identidade , assim como returnfaz para Monad(que é um monóide na categoria de endofuncionadores ).

Considere puree liftA2:

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

Se você apertar os olhos um pouco, poderá imaginar que liftA2é uma operação binária, que também é o que a documentação afirma:

Levante uma função binária para ações.

pure, então, é a identidade correspondente.

Mark Seemann
fonte
6
Exatamente. Applicativesem pureseria um, hm, functor semigroupal em vez de monoidal.
leftaroundabout
20

fmapnem sempre é fácil. Especificamente, pureé o que permite apresentar f(onde festá Applicative) quando você ainda não o possui. Um bom exemplo é

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

Ele pega uma lista de "ações" que produzem valores e a transforma em uma ação que produz uma lista de valores. O que acontece quando não há ações na lista? O único resultado sensato é uma ação que não produz valores:

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

Se você não tivesse pure, seria obrigado a exigir uma lista não vazia de ações. Você definitivamente poderia fazê-lo funcionar, mas é como falar sobre adição sem mencionar 0 ou multiplicação sem 1 (como outros já disseram, porque Applicatives são monoidais). Você encontrará repetidamente casos extremos que seriam facilmente resolvidos, puremas que precisam ser resolvidos por restrições estranhas em suas entradas e outros band-aids.

HTNW
fonte