Por que a produção mútua torna ArrowApply e Monads equivalentes, ao contrário de Arrow e Applicative?

8

Aqui está o post que eu vou me referir . Além disso, vou usar os mesmos trechos do OP nessa pergunta para não separar os materiais .

É sabido que uma ArrowApplyinstância produz uma Mônada e vice-versa:

newtype ArrowMonad a b = ArrowMonad (a () b)

instance Arrow a => Functor (ArrowMonad a) where
    fmap f (ArrowMonad m) = ArrowMonad $ m >>> arr f

instance Arrow a => Applicative (ArrowMonad a) where
   pure x = ArrowMonad (arr (const x))
   ArrowMonad f <*> ArrowMonad x = ArrowMonad (f &&& x >>> arr (uncurry id))

instance ArrowApply a => Monad (ArrowMonad a) where
    ArrowMonad m >>= f = ArrowMonad $
        m >>> arr (\x -> let ArrowMonad h = f x in (h, ())) >>> app

newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }

instance Monad m => Category (Kleisli m) where
    id = Kleisli return
    (Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)

instance Monad m => Arrow (Kleisli m) where
    arr f = Kleisli (return . f)
    first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
    second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))

E até me deparar com o post mencionado acima, senti que esse trecho era uma prova plausível da equivalência de ArrowApplye Monadclasses. No entanto, ter o conhecimento de que Arrow e Applicative não são, de fato, equivalentes e o seguinte snippet me deixou curioso sobre a prova completa da equivalência de Monade ArrowApply:

newtype Arrplicative arr o a = Arrplicative{ runArrplicative :: arr o a }

instance (Arrow arr) => Functor (Arrplicative arr o) where
    fmap f = Arrplicative . (arr f .) . runArrplicative

instance (Arrow arr) => Applicative (Arrplicative arr o) where
    pure = Arrplicative . arr . const

    Arrplicative af <*> Arrplicative ax = Arrplicative $
        arr (uncurry ($)) . (af &&& ax)

newtype Applicarrow f a b = Applicarrow{ runApplicarrow :: f (a -> b) }

instance (Applicative f) => Category (Applicarrow f) where
    id = Applicarrow $ pure id
    Applicarrow g . Applicarrow f = Applicarrow $ (.) <$> g <*> f

instance (Applicative f) => Arrow (Applicarrow f) where
    arr = Applicarrow . pure
    first (Applicarrow f) = Applicarrow $ first <$> f

> Assim, se você viaja através do aplicativo, perde alguns recursos. É óbvio que, se os exemplos forem fornecidos, ainda não entendi como o "round-trip" através do Monad preserva todos os recursos ArrowApply, pois inicialmente tínhamos uma seta que depende de alguma entrada ( a b c), mas no final, acabamos com uma seta forçada a um invólucro que tem o tipo de unidade como seu tipo de entrada ( ArrowMonad (a () b)).

É óbvio que estou fazendo algo terrivelmente errado aqui, mas não consigo entender exatamente o que.

Qual é a prova completa de que ArrowApplye Monadsão equivalentes?

Quais são os exemplos de desigualdade Arrowe Applicativeexplicação? Um generaliza outro?

Qual é a interpretação de toda essa situação no cálculo de flechas e na teoria das categorias?

Apreciaria explicações e dicas completas que poderiam ajudar a elaborar uma prova plausível de si mesmas.

Zhiltsoff Igor
fonte

Respostas:

3

como inicialmente tínhamos uma seta que depende de alguma entrada ( a b c), mas no final, acabamos com uma seta forçada a um invólucro que tem o tipo de unidade como seu tipo de entrada ( ArrowMonad (a () b))

Acho que esse é o ponto central da confusão e, de fato, é confuso. Eu gosto de pensar em flechas como principalmente morfismos em uma categoria monoidal cartesiana, onde você não entenderia isso, mas a Arrowclasse já é realmente mais restritiva do que isso graças a arr- o que fornece um functor de Hask para a categoria. Mas, surpreendentemente, isso também implica que você obtém um mapeamento na outra direção: qualquer flecha pode ser substituída por uma função que produz apenas uma flecha de domínio trivial. Concretamente,

arrAsFunction :: Arrow k => k x y -> (x -> k () y)
arrAsFunction φ x = φ <<< arr (const x)

Ok, isso por si só não seria muito inovador - talvez tenhamos descartado algumas informações aqui? - mas com ArrowApplyisso na verdade é um isomorfismo : você pode recuperar a flecha original por meio de

retrieveArrowFromFunction ::  k x y .
          ArrowApply k => (x -> k () y) -> k x y
retrieveArrowFromFunction f = arr f' >>> app
 where f' :: x -> (k () y, ())
       f' x = (f x, ())

... que é exatamente o que é usado na Monad (ArrowMonad a)instância.

Portanto, o resultado é:, arrexigindo que você possa incorporar qualquer função Haskell na categoria, reforça que a categoria se resume basicamente a funções com algum invólucro ao redor do resultado , faça IOW como as setas de Kleisli.

Confira algumas outras hierarquias da teoria das categorias para ver que isso não é uma característica fundamental das categorias monoidais cartesianas, mas realmente um artefato do functor Haskk . Por exemplo, em categorias restritas, eu espelhei as classes padrão de perto, com PreArrowa classe de categorias monoidais cartesianas, mas deliberadamente as mantive arrfora dela e não a tornamos específica para Hask , porque isso enfraquece demais as capacidades da categoria. e faz com que seja quase equivalente a Hask -Kleisli.

leftaroundabout
fonte
Obrigado pela sua resposta - faz muito mais sentido agora! Existe uma razão pela qual essa parte do isomorfismo é muitas vezes deixada de fora quando se fala em equivalência ArrowApply / Monad? Ou simplesmente confundi uma liderança intuitiva com uma prova estrita?
Zhiltsoff Igor 24/01
Bem, “as mônadas são equivalentes a flechas que satisfazem o tipo isomorfismo ABA → (1 ↝ B )” ... isso é bem ali no resumo do papel alheio / meticuloso / promíscuo. Por que esse ponto de vista não costuma ser tão discutido, eu não sei.
leftaroundabout