如何在Haskell中的另一个函数的参数上映射函数?

Auf*_*ben 4 haskell

所以最初我写道:

xs <- getAddrInfo (Just hints) (Just addr) (Just port)
Run Code Online (Sandbox Code Playgroud)

那么在我看来,函数'Just :: a - > Maybe a'有点"映射"在'hints','addr'和'port'上,所以我提出了类似这样的东西:

map_arg g f a b c = f (g a) (g b) (g c)
xs <- map_arg Just getAddrInfo hints addr port
Run Code Online (Sandbox Code Playgroud)

但GHC期望(ga),(gb)和(gc)属于同一类型,因此不进行类型检查.

有没有办法做到这一点,或者更一般地说,有没有办法将函数映射到另一个函数的参数?

Ear*_*ine 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)
Run Code Online (Sandbox Code Playgroud)

对于您的情况,如果您选择不g作为参数,您可以这样做

map_just f a b c = f (g a) (g b) (g c) where g = Just
xs <- map_just getAddrInfo hints addr port
Run Code Online (Sandbox Code Playgroud)

或者你只能给出类型签名g:

map_arg (g :: forall b.b -> a b) f a b c = f (g a) (g b) (g c)
Run Code Online (Sandbox Code Playgroud)

要绕过多态类型签名,请记住我们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)
Run Code Online (Sandbox Code Playgroud)

(Pointedfor 的实现MaybeJust你想要的)

要有一个通用版本,请注意

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
Run Code Online (Sandbox Code Playgroud)

看到了吗?你只需要map1和所有其他人只是简单的组合!

  • @misterbee我认为这是Hindley-Milner型系统的限制,它是基于GHC的.没有多态类型签名,Haskell无法进行多态类型推断,除非使用`where`或`let`子句绑定变量. (2认同)