2016-05-08 4 views
4

Data.Map.unionWithと似た関数を書こうとしましたが、失敗する可能性があります。元のものはMaybeを使用しています。これは確かにMonadです。したがって、モナドなものは私のためにうまくいきます。私はunionWithの型の要件を満たすために純粋にそれをfmappedしたので、Applicativeで書き直すことができるのだろうかと思います。または、unionWithの代わりにData.Mapの他の関数を使用しますか?このunionWithのような関数をMonadの代わりにApplicativeで書き直すことはできますか?

{-# 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 
+0

AFAICSにそれを簡略化することができ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 

を取得し、 'unionWithM'は不可能です:' unionWith'は 'v'結果を養うことができます'v - > v - > mv'の' v - > v - > mv'の別の呼び出しに '' v - > v - > mv'これは、モナドを必要とするKelisli構成に近いです。 – chi

答えて

7

はい、中間データ構造が必要です。 問題は、あなたのf'm a -> m a -> m aの理由で、関数を適用する前にマップの値をラップすることです。 ff'に変換するには、join、つまりMonadが必要です。そのトリックは、結合の後に関数を適用することです。 (Maybe a, Maybe a)はちょっと混乱している可能性があるので、代わりにTheseデータ型を使用できます。我々はそれをロールアウトする場合は、あなたが

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

私は 'なし'の 'の'を参照してください。 – dfeuer

+0

私はこのソリューションを気に入っていないと言わざるを得ません。 –

+0

@dfeur確かに。 – mb14

関連する問題