Consider these two functions in Haskell:
replace_snd :: b -> Maybe (a, b) -> Maybe (a, b)
replace_snd y' (Just (x, y)) = Just (x, y')
replace_snd _ Nothing = Nothing
inject_snd :: Maybe b -> (a, b) -> Maybe (a, b)
inject_snd (Just b') (a, b) = Just (a, b')
inject_snd Nothing _ = Nothing
replace_snd replaces the second element of a pair, or returns Nothing if there is no pair:
> replace_snd 30 (Just (1, 2))
Just (1,30)
> replace_snd 30 Nothing
Nothing
inject_snd replaces the second element, or returns Nothing if there is no replacement:
> inject_snd (Just 30) (1, 2)
Just (1,30)
> inject_snd Nothing (1, 2)
Nothing
Also consider their symmetric counterparts replace_fst, inject_fst that act on the first element of a pair:
replace_fst :: a -> Maybe (a, b) -> Maybe (a, b)
replace_fst x' (Just (x, y)) = Just (x', y)
replace_fst _ Nothing = Nothing
inject_fst :: Maybe a -> (a, b) -> Maybe (a, b)
inject_fst (Just a') (a, b) = Just (a', b)
inject_fst Nothing _ = Nothing
My question is this: Which of these four functions can be written more compactly using built-in functions such as monadic operators? And how?
For example, I've realized that inject_snd is just (mapM . const), because Maybe is a Monad and ((,) a) is a Traversable:
> (mapM . const) (Just 30) (1, 2)
Just (1,30)
> (mapM . const) Nothing (1, 2)
Nothing
Are there similarly compact equivalents for the other three functions?
Alternatively
fmap . fmap . const, which doesn't require theArrowimport... but I dislike the(a,)functor, and this wouldn't extend toreplaceFst. WithArrowhowever, it's just as easy:The
injects are a bit more awkward, but can still readily be done with an application-operator section:Again, you could replace
secondwithfmap, but please don't.This can also be written
Of course, if you're ok with flipping the signature around, then the
flipis unnecessary: