Tại sao năng suất lẫn nhau làm cho ArrowApply và Monads tương đương nhau, không giống như Arrow và Applicative?


8

Đây là bài viết SO tôi sẽ đề cập đến . Ngoài ra, tôi sẽ sử dụng các đoạn giống như OP trong câu hỏi đó để không tách các tài liệu .

Người ta biết rằng một ArrowApplythể hiện mang lại một Monad và ngược lại:

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))

Và cho đến khi tôi tình cờ thấy bài đăng được giới thiệu ở trên, tôi cảm thấy rằng đoạn trích này là một bằng chứng xác thực cho sự tương đương ArrowApplyMonadcác lớp. Tuy nhiên, trên thực tế , có kiến ​​thức rằng Mũi tên và Ứng dụng không thực sự tương đương và đoạn trích sau đây khiến tôi tò mò về bằng chứng đầy đủ về sự tương đương của MonadArrowApply:

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

> Vì vậy, nếu bạn đi vòng qua ứng dụng, bạn sẽ mất một số tính năng. Rõ ràng là nếu các ví dụ được cung cấp, nhưng tôi không nắm bắt được cách "vấp vòng" thông qua Monad bảo tồn tất cả các tính năng của ArrowApply vì ban đầu chúng tôi có một mũi tên phụ thuộc vào một số đầu vào ( a b c) nhưng cuối cùng, chúng tôi kết thúc bằng một mũi tên buộc vào một trình bao bọc có loại đơn vị là loại đầu vào ( ArrowMonad (a () b)).

Rõ ràng là tôi đang làm điều gì đó cực kỳ sai ở đây, nhưng tôi không thể hiểu chính xác điều gì.

Bằng chứng đầy đủ đó là gì ArrowApplyMonadtương đương?

Các ví dụ về sự không tương đương ArrowApplicativetài khoản cho những gì? Có một cái chung chung khác?

Giải thích toàn bộ tình huống đó trong tính toán mũi tên và lý thuyết thể loại là gì?

Tôi sẽ đánh giá cao cả những lời giải thích đầy đủ và những lời khuyên có thể giúp người ta tự đưa ra một bằng chứng chính đáng.

Câu trả lời:


3

vì ban đầu chúng tôi có một mũi tên phụ thuộc vào một số đầu vào ( a b c) nhưng cuối cùng, chúng tôi kết thúc với một mũi tên buộc vào một trình bao bọc có loại đơn vị là loại đầu vào của nó ( ArrowMonad (a () b))

Tôi đoán đây là điểm trung tâm của sự nhầm lẫn, và thực sự nó là khó hiểu. Tôi thích nghĩ về các mũi tên chủ yếu là các hình thái trong thể loại đơn hình cartes, nơi bạn sẽ không có được điều này, nhưng Arrowlớp học thực sự hạn chế hơn thế - nhờ arrđó đưa bạn một functor từ Hask vào danh mục. Nhưng, hơi ngạc nhiên, điều đó cũng đòi hỏi bạn phải có một ánh xạ theo hướng khác : bất kỳ mũi tên nào cũng có thể được thay thế bằng một hàm chỉ mang lại một mũi tên của miền tầm thường. Cụ thể,

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

Ok, một mình nó sẽ không quá hấp dẫn - có lẽ chúng ta đã loại bỏ một số thông tin ở đây? - nhưng với ArrowApplyđiều này thực sự là một sự đẳng cấu : bạn có thể lấy lại mũi tên ban đầu bằng cách

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, ())

... đó chính xác là những gì được sử dụng trong Monad (ArrowMonad a)ví dụ.

Vì vậy, kết quả cuối cùng là : arr, bằng cách yêu cầu bạn có thể nhúng bất kỳ chức năng Haskell nào trong danh mục, thực thi rằng danh mục về cơ bản làm sôi các chức năng với một số trình bao quanh kết quả , IOW một cái gì đó giống như mũi tên Kleisli.

Kiểm tra một số hệ thống phân cấp lý thuyết thể loại khác để thấy rằng đây không phải là một tính năng cơ bản của các thể loại đơn hình cartes, nhưng thực sự là một tạo tác của Haskk functor. Ví dụ như trong chế danh mục tôi đã nhân đôi các lớp học tiêu chuẩn chặt chẽ, với PreArrownhư lớp các loại monoidal Descartes, nhưng cố tình giữ arrra khỏi nó và không làm cho nó cụ thể để Hask , bởi vì đó dumbs xuống khả năng của các loại quá nhiều và khiến nó gần như tương đương với Hask -Kleisli.


Cảm ơn câu trả lời của bạn - bây giờ nó có ý nghĩa hơn nhiều! Có một lý do tại sao phần đó với sự đẳng cấu thường không được xem xét khi nói về sự tương đương của ArrowApply / Monad? Hay tôi chỉ đơn giản là nhầm một dẫn trực quan cho một bằng chứng nghiêm ngặt?
Zhiltsoff Igor

Vâng, “monads tương đương với mũi tên đáp ứng các loại đẳng cấu MộtBMột → (1 ↝ B )” ... đó là ngay tại đó một cách trừu tượng của / tỉ mỉ / giấy bừa bãi không biết gì. Tại sao POV này thường không được thảo luận nhiều, tôi không biết.
rời khỏi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.