应用扫描参数从右到左

时间:2016-04-16 01:03:32

标签: haskell ghc

我遇到过几种情况,我想使用适用的风格f <$> x1 <*> x2 <*> x3但是从右到左扫描应用参数,而不是从左到右扫描。

当然,如果我把它带到一个单一的背景中,我可以毫无问题地做到这一点:

liftM3' :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3' f x1 x2 x3 = do { x3' <- x3; x2' <- x2; x1' <- x1; return f x1' x2' x3' }

所以,对于我的问题:是否有一些通用方法可以在仅Applicative(可能是新类型包装器)的上下文中完成此操作,如果没有,为什么不能有一个 。也就是说,欢迎任何有关此问题的优雅解决方案或解决方法的见解。

除了:我的解决方案是定义新的右关联运算符,但解决方案绝不优雅。

编辑:这是我的解决方案(我有兴趣知道标准库中是否有相同的东西),如果我需要Monad

newtype Reverse m a = Reverse (m a)

instance Monad m => Functor (Reverse m) where
  f `fmap` x = pure f <*> x

instance Monad m => Applicative (Reverse m) where
  pure x = Reverse $ return x
  (Reverse f) <*> (Reverse x) = Reverse $ do { x' <- x; f' <- f; return $ f' x' }

2 个答案:

答案 0 :(得分:3)

Backwards类型与Reverse类似,属于半标准套餐。

答案 1 :(得分:0)

  

当然,如果我把它带到一个单一的背景中,我可以毫无问题地做到这一点:

不要忘记f只是一个功能。因此,您可以简单地定义另一个函数,该函数以另一个顺序获取参数,然后回退到通常的应用组合器:

-- | Lifts the given function into an applicative context.
-- The applicative effects are handled from right-to-left
-- e.g. 
-- >>> liftA3 (\_ _ _ -> ()) (putStr "a") (putStr "b") (putStr "c")
-- will put "cba" on your console.
liftA3Rev :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3Rev f x y z = f' <$> z <*> y <*> x
  where
    f' = \c b a -> f a b c
但是,这可能要么不可能,要么很难用运营商写这个。这是由于部分应用的性质。请注意,对于f :: Int -> Char -> BoolApplicative f => f Int,表达式f <$> x 类型为Applicative f => f (Char -> Bool)。我们总是在左端“丢失”类型,而不是在右端。如果你改变了参数的顺序,那就再简单了:

(>*>) :: Applicative f => f a -> f (a -> b) -> f b
(>*>) = flip (<*>)
infixr 4 >*> -- right associative

liftA3Rev' :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3Rev' f x y z = z >*> y >*> x >*> pure f
相关问题