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

Haskell 我们可以为WrappedArrow定义Monad实例吗?,haskell,monads,arrows,Haskell,Monads,Arrows,是Applicative的一个实例,但是否可以将其设置为Monad(如果箭头为ArrowApply),则可能会出现这种情况 编辑: 我最初的目的是为Kleisli(包装)创建一个Monad实例,这样我就可以编写 runWithInput input $ do action1 action2 action3 ... runWithInput input $ do action1 action2 action3 ... 而不是 do output1 <-

Applicative
的一个实例,但是否可以将其设置为
Monad
(如果箭头为
ArrowApply
),则可能会出现这种情况

编辑:

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

runWithInput input $ do
  action1
  action2
  action3
  ...
runWithInput input $ do
  action1
  action2
  action3
  ...
而不是

do
  output1 <- action1 input
  output2 <- action2 output1
  output3 <- action3 output2
  ...
do
  output1 <- action1 input
  output2 <- action2 output1
  output3 <- action3 output2
  ...
我需要的是模拟的
>
,即b而不是第二个
a

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

因此,如果我想用
do
以这种方式对操作进行排序,我想我必须使用
StateT
或自定义monad,因为这是一个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
您可以通过
(>)
的实例获得
箭头交换的一些直觉:

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

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

runWithInput input $ do
  action1
  action2
  action3
  ...
runWithInput input $ do
  action1
  action2
  action3
  ...
而不是

do
  output1 <- action1 input
  output2 <- action2 output1
  output3 <- action3 output2
  ...
do
  output1 <- action1 input
  output2 <- action2 output1
  output3 <- action3 output2
  ...
WrappedArrow
Applicative
的一个实例,但它是否可以成为
Monad
(如果箭头是
ArrowApply
),则可能是

我将把<代码> WrdAdRave</代码>放在一边,并考虑微妙不同的问题:“我们能成功地实现<代码>实例ARROWEY Y= > Monad(Y R)?”这个问题的答案是“是”。一种证明它的方法依赖于chi提到的新类型

newtype ArrowMonad a b = ArrowMonad (a () b)
。。。以及以下同构(参见和第18页):

ArrowMonad
为我们提供了一个monad实例,我们可以通过
kleislify
使用该实例,并为生成的函数提供一个公共参数(换句话说,我们通过函数的应用程序实例使用
ArrowMonad
绑定):

相关的
return
也是
ArrowMonad
一个,列在相应的样板层中:

returnY :: ArrowApply y => a -> y r a
returnY x = unkleislify $ \r -> (\(ArrowMonad am) -> am) (return x)
然而,这并不能回答你的问题。为此,
bindY
returnY
应该与
WrappedArrow的
Applicative
实例一致;也就是说,我们应该有
returnY x=arr(const x)
,我们可以用
bindY
returnY
编写的
ap
应该相当于
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  
我不知道对于任何
箭头应用
,是否可以简化为
arr(const x)
。也许能够翻转箭头(正如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做同样的操作,但我不知情的猜测是会出现类似的情况。

也许你想要?当
b
不是
()
时,我想定义一个合理的monad实例更为棘手。为了定义这样的实例,您还需要一个函数
swap::forall x y z。arr x(arr y z)->arr y(arr x z)
;然后
>==\xf->swap(arrf)&&x>>应用程序
。在
base
中为
箭头
实例定义这样一个函数相当容易,但我不能说它在一般情况下有多有用。关于编辑:您可能已经知道了,但无论如何值得一提的是,您可以改为编写
action1>=>action2>=>action3
(>=>)
是字面上的
(>>)
用于Kleisli arrows)。@duplode当然,但我真的想要一个好看的do符号(它是Shake文件,我希望它看起来非常必要)。考虑到base中的类似函数,
ArrowFlip
flip
可以说是更透明的名称。@duplode我完全同意!我最初是这样写的,但这意味着对于我的示例实例,我必须导入Prelude qualified,然后使用qualified
翻转
。我认为这可能不值得那真的很烦人。事实上,我一时忘记了,在玩这个问题的时候,我实际上在GHCi中定义了一个
fleep
函数:)谢谢你提醒我
rebindabletsyntax
!在
ApplicativeDo
变得足够聪明,可以将
*>
而不是
>
放置之前,它也应该很有用。()昨晚我做了类似的事情,我考虑添加一个
Monoid
Default
约束(来处理
()
的问题)。但我不确定这是否能满足
Monad
定律。我的直觉说不是。。。很好的解释!
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
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 (\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)