我可以用Applicative而不是Monad重写这个类似unionWith的函数吗?

Cos*_*una 5 monads dictionary haskell applicative

我试着写一个类似于Data.Map.unionWith的函数,但可能会失败.原来的人使用了Maybe,这确实是Monad,所以monadic对我来说效果很好.但是我想知道它是否可以用Applicative重写,因为我用纯粹的fmap来满足unionWith的类型要求.或者使用Data.Map中的其他函数而不是unionWith?

{-# LANGUAGE RankNTypes #-}
import Control.Monad
import Data.Map
unionWithM :: (Monad m, Traversable t)
          => (forall a. (a -> a -> a)
              -> t a
              -> t a
              -> t a
             )
          -> (v -> v -> m v)
          -> t v
          -> t v
          -> m (t v)
unionWithM u f a b = sequenceA (u f' (pure <$> a) (pure <$> b))
  where f' x y = join $ f <$> x <*> y

unionWithOriginal :: Ord k => (a -> a -> Maybe a) -> Map k a -> Map k a -> Maybe (Map k a)
unionWithOriginal f a b = sequenceA (unionWith f' (Just <$> a) (Just <$> b))
  where f' x y = join $ f <$> x <*> y
Run Code Online (Sandbox Code Playgroud)

mb1*_*b14 7

是的,你可以,但你需要一个中间数据结构.问题是你在应用函数之前包装了Map的值,这就是你f'的类型的原因m a -> m a -> m a.转变ff'你需要的join,即Monad.诀窍是在联合之后应用函数.为此你可以使用(Maybe a, Maybe a)哪个有点乱,所以你可以使用这些数据类型.如果我们手动推出它你就得到了

data These a b = That a | This b | These a b

unionWith' f a b = let theses = unionWith These (That <$> a) (This <$> b)
                   in sequenceA (f' <$> theses)
    where f' (That a) = pure a
          f' (This b) = pure b
          f' (These a b) = f a b
Run Code Online (Sandbox Code Playgroud)

如果您使用该these软件包,则可以将其简化为

 unionWith'' f a b = sequenceA $ alignWith (these pure pure f)  a b
Run Code Online (Sandbox Code Playgroud)