Em primeiro lugar:
Qualquer mônada também é um função aplicadora e qualquer função aplicadora é um função.
Isso é verdade no contexto de Haskell, mas (lendo Applicative
como "forte função monoidal relaxada") não geralmente, pela razão bastante trivial de que você pode ter funções "aplicativas" entre diferentes categorias monoidais, enquanto mônadas (e comônadas) são endofuncionadoras .
Além disso, identificar-se Applicative
com fortes funcionadores monoidais frouxos é um pouco enganador, porque justificar o nome (e a assinatura do tipo (<*>)
) requer um funcionamento entre categorias monoidais fechadas que preserva a estrutura monoidal e o hom interno . Isso poderia ser plausivelmente chamado de "função monoidal fechada frouxa", exceto que um função entre categorias fechadas monoidais que preserva uma propriedade preserva a outra da maneira óbvia . Como Applicative
descreve apenas endofuncionadores em Hask preservando a estrutura monoidal de (,)
, suas instâncias ganham muitas propriedades automaticamente, incluindo sua força , que pode ser elidida.
A aparente conexão com Monad
é sem dúvida um artefato das limitações implícitas em Applicative
fazer com que aspectos de suas respectivas estruturas monóides coincidam, uma feliz coincidência que infelizmente não sobrevive à dualização.
Apenas como um comonad numa categoria é um mônade em C o p , uma oplax monoidal functor C → D é um relaxado monoidal functor C o p → D O p . Mas H um s k o P é não monoidal fechada , e um co que não incluem a aplicação de função quase méritos do nome. De qualquer forma, o resultado não seria muito interessante:CCo p C→ DCo p→ Do pHa s ko pApplicative
class (Functor f) => CoMonoidal f where
counit :: f () -> ()
cozip :: f (a, b) -> (f a, f b)
Poderíamos imaginar uma noção de "colax closed functor", que pareceria muito mais Applicative
se existisse. Infelizmente, não é (para o melhor do meu conhecimento) um círculo fechado em tudo: em H uma s k corresponde ao morphisms b → um em H uma s k o P , mas não funciona como um hom interno lá - porque as setas são invertidas, algum tipo de co-função seria necessária, o que não podemos definir em geral para H a s k .Ha s ko pnewtype Op b a = Op (a -> b)
Ha s kb → aHa s ko pOp b a
Ha s k
Se simplesmente fingirmos que "os functores fechados colax" existiam para e, além disso, funcionasse da maneira que esperávamos ingenuamente, um co- baseado nisso provavelmente seria assim:Ha s kApplicative
class (Functor f) => CoApplicative f where
copure :: f a -> a
coap :: (f a -> f b) -> f (a -> b)
Adicionar duplicate :: f a -> f (f a)
a copure
isso produziria uma comonada (supondo que as leis sejam cumpridas), é claro. Mas não existe uma relação óbvia entre coap
- o que quer que seja - e extend :: (f a -> b) -> f a -> f b
. Comparando os tipos torna-se claro que a dualização está acontecendo de maneiras diferentes: as estruturas comonoidal subjacente duplicate
e cozip
têm pouco a ver um com o outro ou com coap
(que provavelmente não faz sentido de qualquer maneira), enquanto liftA2 (,)
e (<*>)
são equivalentes e podem ser derivadas de join
.
Outra maneira possível de dualizar Applicative
, que tem ainda menos a ver com comônadas, é considerar os funcionamentos monoidais contravariantes:
class (Contravariant f) => ContraMonoidal f where
contraunit :: f a
contrazip :: f a -> f b -> f (Either a b)
Mas este colide contra as mesmas questões como acima, ou seja, que não é um círculo fechado. Se fosse, teríamos algum tipo de tal forma que podemos escrever funções como e e assim por diante que realmente funcionou como esperado.Ha s ko pb <~ a
contracurry :: (Either c b <~ a) -> (c <~ (b <~ a))
contraapply :: b -> Either a (a <~ b)
Ha s kCoApplicative
No entanto, em uma categoria fechada monoidal mais hospitaleira à dualização, você pode ter melhor sorte. Em particular, acredito que ambos Kleisli (Cont r)
e sua categoria oposta são fechados monoidalmente, de modo que possa ser um contexto melhor para explorar essas idéias.