WrappedArrow
is an instance of Applicative
, but can it be made a Monad
(probably if the arrow is ArrowApply
)?
instance ArrowApply a => Monad (WrappedArrow a b) where
return = pure
(>>) = (*>)
(>>=) = ???
EDIT:
My initial purpose was to have a Monad instance for (wrapped) Kleisli, so I could write
runWithInput input $ do
action1
action2
action3
...
instead of
do
output1 <- action1 input
output2 <- action2 output1
output3 <- action3 output2
...
But I realized that won't make desirable sense. Stripped of newtypes, Kleisli f a b >> Kleisli f a c
is
(a -> f b) -> (a -> f c) -> (a -> f c)
And what I need is analog of >>>
, i.e. b instead of second a
:
(a -> f b) -> (b -> f c) -> (a -> f c)
So I suppose I will have to use StateT
or a custom monad if I want to sequence actions in this manner with do
.
Since this is an XY problem, I'll answer both the question you asked, and the question you probably wanted to ask:
WrappedArrow
is an instance ofApplicative
, but can it be made aMonad
(probably if the arrow isArrowApply
)?
Yes it can, but you'll need more constraints. In fact, I think there are several ways to do this. For example, you could take the approach suggested by @user2407038:
class Arrow a => ArrowSwap a where
swap :: a b (a c d) -> a c (a b d)
instance (ArrowApply a, ArrowSwap a) => Monad (WrappedArrow a b) where
return = pure
WrapArrow m >>= f = WrapArrow $ swap (arr (unwrapArrow . f)) &&& m >>> app
You can get some intuition for ArrowSwap
via its instance for (->)
:
instance ArrowSwap (->) where
swap :: (b -> (c -> d)) -> c -> b -> d
swap = flip
Of course, it isn't immediately clear that this is useful...
My initial purpose was to have a Monad instance for (wrapped) Kleisli, so I could write
runWithInput input $ do action1 action2 action3 ...
instead of
do output1 <- action1 input output2 <- action2 output1 output3 <- action3 output2 ...
This is what RebindableSyntax
is for:
{-# LANGUAGE RebindableSyntax #-}
import Control.Monad (>=>)
action1 :: Monad m => T1 -> m T2
action2 :: Monad m => T2 -> m T3
action3 :: Monad m => T3 -> m T4
action4 :: Monad m => T1 -> m T4
action4 = let (>>) = (>=>) in do
action1
action2
action3