所以最初我写道:
xs <- getAddrInfo (Just hints) (Just addr) (Just port)
然后在我看来,函数'Just :: a - &gt;也许'有点'映射“超过'提示','地址'和'端口',所以我想出了类似的东西:
map_arg g f a b c = f (g a) (g b) (g c)
xs <- map_arg Just getAddrInfo hints addr port
但GHC期望(g a),(g b)和(g c)属于同一类型,因此不进行类型检查。
有没有办法做到这一点,或者更一般地说,是否有办法将函数映射到另一个函数的参数上?
答案 0 :(得分:5)
最通用的类型签名看起来像
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)
对于您的情况,如果您选择不将g
作为参数,则可以执行
map_just f a b c = f (g a) (g b) (g c) where g = Just
xs <- map_just getAddrInfo hints addr port
或者您只能将类型签名提供给g
:
map_arg (g :: forall b.b -> a b) f a b c = f (g a) (g b) (g c)
要绕过多态类型签名,请记住我们有Control.Functor.Pointed
,因此您可以使用它:
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)
(Pointed
Maybe
的实施Just
是您想要的)
要获得通用版本,请注意
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
看到了吗?你只需要map1
而其他所有人只是简单的组合!
答案 1 :(得分:4)
简短的回答是否定的(如果你在讨论一个适用于任意数量参数的通用map_arg
)。
您可以使用Oleg级别的魔术来实现这一目标,但如果您只是在寻找改进代码的方法,那么这里的改进并不多。
答案 2 :(得分:2)
只需向map_arg
添加类型注释,并使g
多态。
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)
您需要Rank2Types
或RankNTypes
分机才能执行此操作。