Reputation: 857
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?
Upvotes: 4
Views: 194
Reputation: 10436
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!
Upvotes: 5
Reputation: 38718
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.
Upvotes: 4
Reputation: 6703
Just add a type annotation to map_arg
and make g
polymorphic.
map_arg :: (forall a. a -> Maybe a) ->
(Maybe AddrInfo -> Maybe HostName -> Maybe ServiceName -> IO [AddrInfo]) ->
AddrInfo -> HostName -> ServiceName -> IO [AddrInfo]
map_arg g f a b c = f (g a) (g b) (g c)
You need Rank2Types
or RankNTypes
extension to do this.
Upvotes: 2