Haskell 如何声明let中定义的函数类型

Haskell 如何声明let中定义的函数类型,haskell,typechecking,nested-function,Haskell,Typechecking,Nested Function,我想写一些像: f :: (a -> b) -> a -> c -> b f g = let inner :: a -> c -> b inner x y = g x in inner 但这给了我一个错误,因为它不知道我试图将声明中相同的“a”和“b”类型引用为f 如何显式地为inner指定正确的类型?您需要扩展名。您还需要在签名中添加一个显式的,用于所有的ab c.,它指示绑定整个定义范围内的变量 {-# LANGUAGE Sco

我想写一些像:

f :: (a -> b) -> a -> c -> b
f g =
   let inner :: a -> c -> b
       inner x y = g x
   in inner
但这给了我一个错误,因为它不知道我试图将声明中相同的“a”和“b”类型引用为f

如何显式地为inner指定正确的类型?

您需要扩展名。您还需要在签名中添加一个显式的
,用于所有的ab c.
,它指示绑定整个定义范围内的变量

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall a b c . (a -> b) -> a -> c -> b
f g =
   let inner :: a -> c -> b
       inner x y = g x
   in inner

实现这一点的一种方法是通过将g设置为内部参数来绑定外部和内部类型,如下所示

f g =
   let inner :: (a->b)->a -> c -> b
       inner g x y = g x
   in inner g

这确实会稍微改变你的结构。。。。并且可能首先否定了使用内部let的原因,但在许多情况下(取决于较大的程序),这可能会有所帮助。

您需要扩展
ScopedTypeVariables
,您可能还需要为所有AB c.添加一个显式的
。在这种情况下,您实际上不需要内部类型签名,甚至可以选择以
f g=const的形式编写函数。g
(甚至
f=(常数)
)以获得相同的行为。您甚至不需要外部类型签名,GHC使用
const正确地推断它。g
@bheklillr,类型签名是很好的文档。如果有问题的程序员认为有一个类型签名有助于澄清问题,那么这是一个很好的理由将其放入其中。@dfeur当然,我总是在我的代码中的顶级函数上放置类型签名,但我在这里的观点是,编译此代码时根本不需要类型签名。ScopedTypeVariables是不必要的,因为编译器可以完全从定义中推断类型。@luqui谢谢你,我真的不知道为什么它是必要的!