我们可以为 WrappedArrow 定义一个 Monad 实例吗?

问题描述 投票:0回答:2

WrappedArrow
Applicative
的一个实例,但它可以成为
Monad
吗(可能如果箭头是
ArrowApply
)?

instance ArrowApply a => Monad (WrappedArrow a b) where
  return = pure
  (>>) = (*>)
  (>>=) = ???

编辑:

我最初的目的是为(包装的)Kleisli 提供一个 Monad 实例,这样我就可以编写

runWithInput input $ do
  action1
  action2
  action3
  ...

而不是

do
  output1 <- action1 input
  output2 <- action2 output1
  output3 <- action3 output2
  ...

但我意识到这没有任何意义。除去新类型,

Kleisli f a b >> Kleisli f a c

(a -> f b) -> (a -> f c) -> (a -> f c)

我需要的是

>>>
的模拟,即b而不是第二个
a

(a -> f b) -> (b -> f c) -> (a -> f c)

所以我想如果我想用

StateT
以这种方式对操作进行排序,我将不得不使用
do
或自定义 monad。

haskell monads arrow-abstraction
2个回答
3
投票

由于这是一个 XY 问题,我将回答您提出的问题以及您可能想问的问题:

WrappedArrow
Applicative
的实例,但可以将其制成
Monad
(可能如果箭头是
ArrowApply
)?

是的,可以,但你需要更多的限制。事实上,我认为有几种方法可以做到这一点。例如,您可以采用@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

您可以通过

ArrowSwap
的实例获得对
(->)
的一些直觉:

instance ArrowSwap (->) where
  swap :: (b -> (c -> d)) -> c -> b -> d
  swap = flip

当然,目前还不清楚这是否有用......

我最初的目的是为(包装的)Kleisli 提供一个 Monad 实例, 这样我就可以写

runWithInput input $ do
  action1
  action2
  action3
  ...

而不是

do
  output1 <- action1 input
  output2 <- action2 output1
  output3 <- action3 output2
  ...

这就是

RebindableSyntax
的用途:

 {-# 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

1
投票

WrappedArrow
Applicative
的实例,但可以将其制成
Monad
(可能如果箭头是
ArrowApply
)?

我将把

WrappedArrow
暂时放在一边,考虑一下略有不同的问题“我们能否成功实施
instance ArrowApply y => Monad (y r)
?”。这个问题的答案是“是”。演示它的一种方法依赖于
ArrowMonad
新型气提到......

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

...以及以下同构(参见这个cstheory.SE问题的第18页习语是不经意的,箭头是细致的,单子是混杂的):

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
为我们提供了一个 monad 实例,我们可以通过对箭头进行
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
做同样的事情,但我不知情的猜测是会导致类似的情况。

© www.soinside.com 2019 - 2024. All rights reserved.