So initially I wrote:
xs <- getAddrInfo (Just hints) (Just addr) (Just port)
then it seemed to me that the function 'Just :: a -> Maybe a' is kind of "mapped" over 'hints', 'addr', and 'port', so I came up with something like this:
map_arg g f a b c = f (g a) (g b) (g c)
xs <- map_arg Just getAddrInfo hints addr port
but GHC expects (g a), (g b) and (g c) to be of the same type, so this doesn't type check.
Is there a way to do this, or more generically, is there a way to map a function over the arguments of another function?
A most generic type signature would looks like
map_arg :: (forall b.b -> a b) -> (a b -> a c -> a d -> e) -> b -> c -> d -> e
map_arg g f a b c = f (g a) (g b) (g c)
for your case, if you choose not to put g
as a parameter, you can do
map_just f a b c = f (g a) (g b) (g c) where g = Just
xs <- map_just getAddrInfo hints addr port
or you can just give type signature to g
only:
map_arg (g :: forall b.b -> a b) f a b c = f (g a) (g b) (g c)
To bypass the polymorphic type signature, remember we have Control.Functor.Pointed
so you can use it:
map_arg :: Pointed p => (p a -> p b -> p c -> d) -> a -> b -> c -> d
map_arg f a b c = f (point a) (point b) (point c)
(The implementation of Pointed
for Maybe
is Just
what you want)
To have a generalized version, note that
map1 :: Pointed p => (p a -> b) -> a -> b
map1 f = f . point
map2 :: Pointed p => (p a -> p b -> c) -> a -> b -> c
map2 f = map1 . map1 f
map3 :: Pointed p => (p a -> p b -> p c -> d) -> a -> b -> c -> d
map3 f = map2 . map1 f
See that? you only need map1
and all others is just simple combination!
The short answer is no (if you're talking about a generic map_arg
that'd work for any number of arguments).
You might be able to achieve this with Oleg-level type magic, but if you're just looking for the ways to improve your code, there's not much to improve here.
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