【问题标题】:Can I rewrite this unionWith-like function with Applicative instead Monad?我可以用 Applicative 而不是 Monad 重写这个类似 unionWith 的函数吗?
【发布时间】:2016-05-08 04:37:34
【问题描述】:

我试图写一个类似于Data.Map.unionWith的函数,但可能会失败。原来的使用 Maybe,它确实是 Monad,所以 monadic 对我来说很好用。但我想知道它是否可以用 Applicative 重写,因为我用 pure 映射它只是为了满足 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

【问题讨论】:

  • AFAICS,unionWithM 是不可能的:unionWith 可以将v -&gt; v -&gt; m vv 结果提供给v -&gt; v -&gt; m v 的另一个调用。这与需要单子的 Kelisli 组合很接近。

标签: haskell dictionary monads applicative


【解决方案1】:

是的,你可以,但你需要一个中间数据结构。 问题是您在应用函数之前包装了 Map 的值,这就是为什么您的 f'm a -&gt; m a -&gt; m a 类型的原因。要将f 转换为f',您需要join,即Monad。诀窍是在联合之后应用该功能。 为此,您可以使用有点混乱的(Maybe a, Maybe a),因此您可以使用These 数据类型。如果我们手动推出它,你会得到

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

如果您使用 these 包,您可以将其简化为

 unionWith'' f a b = sequenceA $ alignWith (these pure pure f)  a b

【讨论】:

  • 我看到let 没有in
  • 我不得不说,虽然我赞成这个解决方案,但我并不是很喜欢它,好吧,它仍然有效,谢谢。
  • @dfeur 确实如此。固定
  • @CosmiaLuna 好奇。您不喜欢此解决方案的哪些方面?
  • @mb14 不知道,只是有点……,可能是中间数据结构?
猜你喜欢
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 2014-02-06
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多