代码之家  ›  专栏  ›  技术社区  ›  modular

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

  •  2
  • modular  · 技术社区  · 8 年前

    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 或者一个自定义的monad,如果我想用 do .

    2 回复  |  直到 8 年前
        1
  •  3
  •   Alec    8 年前

    由于这是一个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
    
        2
  •  1
  •   Community CDub    8 年前

    WrappedArrow Applicative ,但它能成为 Monad (如果箭头是 ArrowApply )?

    我会把 暂且不谈,考虑一个微妙的不同问题:“我们能否成功实施?” instance ArrowApply y => Monad (y r) ?这个问题的答案是“是”。证明这一点的一种方法是 ArrowMonad 新类型chi提到。。。

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

    …和以下同构(参见。 this cstheory.SE question 第18页,共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
    

    阿罗莫纳德 给我们一个monad实例,我们可以使用 kleislify -使用箭头并为结果函数提供一个公共参数(换句话说,我们使用 阿罗莫纳德 通过函数的应用程序实例绑定):

    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 也是 阿罗莫纳德 一个,在适当的样板层中:

    returnY :: ArrowApply y => a -> y r a
    returnY x = unkleislify $ \r -> (\(ArrowMonad am) -> am) (return x)
    

    然而,这并不能回答你的问题。为了实现这一点, bindY returnY 实用的 实例 拉佩达罗 ; 也就是说,我们应该 returnY x = arr (const x) ,以及 ap 我们可以用 宾迪 返回 应等同于 (<*>) WrappedMonad 例如,我们可以尝试使用相关 阿罗莫纳德 实例。。。

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

    我还没有尝试过这样做 宾迪 ,但我不知情的猜测是,会出现类似的情况。