I tried to write a function similar to Data.Map.unionWith, but may fail. The original one uses Maybe, which indeed is a Monad, so the monadic one just works fine for me. but I wonder if it can be rewritten with Applicative, since I fmapped it with pure just to satisfy the type requirement of unionWith. Or with other function in Data.Map instead of 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
An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.
Monads are not a replacement for applicative functors Instead, every monad is an applicative functor (as well as a functor).
Applicative functor allows the sequencing of multiple independent effects. Functor deals with one effect while applicative functor can deal with multiple independent effects. In other words, applicative functor generalizes functor. In terms of an interface, applicative functor adds pure and apply to functor's map .
The first function allows to transform your input values to a set of values that our Monad can compose. The second function allows for the composition. So in conclusion, every Monad is not a Functor but uses a Functor to complete it's purpose.
Yes you can but you need an intermediate data structure.
The problem is you wrap the value of your Map before applying the function, which is why your f'
is of type m a -> m a -> m a
. To transform f
to f'
you need join
, i.e. a Monad. The trick is to apply the function after the union.
For that you could use (Maybe a, Maybe a)
which is a bit messy, so instead you can use the These data type. If we roll it out manually you get
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
If you use the these
package you can simplify it to
unionWith'' f a b = sequenceA $ alignWith (these pure pure f) a b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With