WrappedArrow
является экземпляром Applicative
, но он может быть сделан Monad
(возможно, если стрелка ArrowApply
)?
вложу WrappedArrow
в сторону на мгновение и рассмотрим тонко другой вопрос «Можно ли успешно реализовать instance ArrowApply y => Monad (y r)
?». Ответ на этот вопрос «да». Один из способов демонстрации он опирается на ArrowMonad
Newtype хи упоминает ...
newtype ArrowMonad a b = ArrowMonad (a() b)
... и изоморфизм (см this cstheory.SE question и страница 18 из Idioms are oblivious, arrows are meticulous, monads are promiscuous):
kleislify :: ArrowApply y => y r a -> (r -> y() a)
kleislify af = \r -> arr (const r) >>> af
unkleislify :: ArrowApply y => (r -> y() a) -> y r a
unkleislify f = arr f &&& arr (const()) >>> app
-- unkleislify . kleislify = kleislify . unkleislify = id
ArrowMonad
дает нам экземпляр монады, который мы можем использовать с помощью kleislify
, - используя стрелки и предоставляя общий аргумент полученным функциям (другими словами, мы используем привязку ArrowMonad
через аппликативный экземпляр для функций):
bindY :: ArrowApply y => y r a -> (a -> y r b) -> y r b
bindY af h = unkleislify $ (\(ArrowMonad am) -> am) . (\r ->
ArrowMonad (kleislify af r) >>= \x -> ArrowMonad (kleislify (h x) r))
Соответствующий return
также является ArrowMonad
один, выдержано в соответствующих слоях шаблонного:
returnY :: ArrowApply y => a -> y r a
returnY x = unkleislify $ \r -> (\(ArrowMonad am) -> am) (return x)
Это, однако, не отвечает на вопрос. Для этого bindY
и returnY
должны соответствовать экземпляру Applicative
WrappedArrow
; то есть мы должны иметь returnY x = arr (const x)
, а ap
мы можем написать bindY
, а returnY
должен быть эквивалентен (<*>)
для WrappedMonad
. Например, мы могли бы попытаться использовать определение соответствующих ArrowMonad
экземпляров ...
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
... расширить (а затем, надеюсь, упростить) returnY
:
returnY
unkleislify $ \r -> (\(ArrowMonad am) -> am) (return x)
unkleislify $ \r -> (\(ArrowMonad am) -> am) (ArrowMonad (arr (const x)))
unkleislify $ \r -> arr (const x)
arr (\r -> arr (const x)) &&& arr (const()) >>> app
arr (const (arr (const x))) &&& arr (const()) >>> app
arr (\r -> (r, r)) >>> arr (const (arr (const x))) *** arr (const()) >>> app
arr (\r -> (arr (const x),())) >>> app
Я понятия не имею, что ли могут быть упрощены до arr (const x)
для любых ArrowApply
. Возможно, возможность переворачивать стрелки (как предлагает Alec и user2407038) поможет избавиться от ()
, но я не справился с этим. В любом случае, для Kleisli
по крайней мере, мы можем продолжить:
arr (\r -> (arr (const x),())) >>> app
Kleisli (\r -> return (arr (const x),())) >>> Kleisli (\(Kleisli f, x) -> f x)
Kleisli ((\r -> return (arr (const x),())) >=> (\(Kleisli f, x) -> f x))
Kleisli ((\r -> return (Kleisli (return . const x),()))
>=> (\(Kleisli f, x) -> f x))
Kleisli (\r -> return (Kleisli (return . const x),())
>>= (\(Kleisli f, x) -> f x))
Kleisli (\r -> (\(Kleisli f, x) -> f x) (Kleisli (return . const x),()))
Kleisli (\r -> (return . const x)())
Kleisli (\r -> return x)
Kleisli (return . const x)
arr (const x)
Я не пытался делать то же самое с bindY
, но мой несведущий догадаться, что подобный сценарий приведет.
Возможно, вы хотите ['Control.Arrow.ArrowMonad'] (https://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Arrow.html#t:ArrowMonad)? Когда 'b' не'() 'Я думаю, сложнее определить разумный экземпляр монады. – chi
Чтобы определить такой экземпляр, вам также потребуется функция 'swap :: forall x y z. arr x (arr y z) -> arr y (arr x z) '; затем '>> = = \ x f -> swap (arr f) &&& x >>> app'. Достаточно легко определить такую функцию для экземпляров 'Arrow' в' base', но я не могу сказать, насколько это полезно в целом. – user2407038
Что касается вашего редактирования: вы, вероятно, уже знаете это, но в любом случае стоит упомянуть, что вместо этого вы можете написать 'action1> => action2> => action3' (' (> =>) 'буквально' (>>>) 'для стрелок Kleisli). – duplode