描述非特定类型的 Haskell 函数的类型签名的方法是什么?
What is the way to describe the type signature of Haskell functions that are not type-specific?
给定像 negate
这样的函数,它具有类型签名:
negate :: Num a => a -> a
我将其描述为 a
是 Num
上下文中的类型(如果您认为我错了请纠正我)。
但我不太确定如何描述类似 last
的东西,它具有类型签名:
last :: [a] -> a
我的猜测是说它不是特定于类型的,它接受一个列表并生成与该列表类型相同的单个值。这是正确的思考方式吗?
首先,a
不是 Num
上下文中的 类型,而是 a 类型有一个 Num
个实例。
Num a => a -> a
是constrained多态类型,而[a] -> a
是无约束多态类型,简称多态类型。在不受约束的情况下,a
可以是任何类型;在受约束的情况下,它必须是遵守给定约束的类型。
在 negate
中,您需要对传递的元素进行 操作 ,在您的情况下,您可以对其应用一些运算符,例如(-)
: negate a = -a
.
您不能为 any 类型定义 negate
,因为您需要能够对其调用 (-)
。你需要一些保证给定的参数将是支持此操作的某种类型。
Num
是一种 class 类型,它为您提供了这样的 - 支持 (-)
的编译时保证,以及其他功能,如 +
、*
,也是。您可以在 docs
中阅读更多相关信息
相比之下,last :: [a] -> a
而不是 (需要)对实际的 a
值做任何事情。它只接受它们和 returns 最后一个。虽然 negate
对 a
值进行操作,但此处 last
对 list 进行操作,但不对其值进行任何操作,它仅传递它们大约。因此,它不需要任何关于它们的知识,因此类型不受约束。
last :: [a] -> a
是 System F 类型
的 Haskell98 语法
last :: ∀ a. [a] -> a
∀ a
可以理解为一种类型级别的lambda绑定,即在实际值级别列表参数之前,函数接受一个类型级别的参数,告诉列表中包含的元素的类型.此 通用量化 使函数 参数化多态 。
通常情况下,类型变量由类型检查器自动插入。在较新的 GHC Haskell 中,您还可以显式应用它们:
Prelude> :set -XTypeApplications
Prelude> :t last @Int
last @Int :: [Int] -> Int
Prelude> last @Double [5,6,7]
7.0
negate
也是参数多态的,但与 last
不同的是,它并不真正“适用于所有”类型,但仅适用于具有 Num
实例(两者都 Int
和 Double
可以,但不可以,例如 Char
)。换句话说,它不仅接受一个额外的参数指定类型,而且接受一个证明它确实有一个Num
实例。这也将由编译器自动插入。
negate :: ∀ a. Num a => a -> a
Prelude> :t negate @Int
negate @Int :: Int -> Int
Prelude> :t negate @Char
<interactive>:1:1: error:
No instance for (Num Char) arising from a use of ‘negate’
给定像 negate
这样的函数,它具有类型签名:
negate :: Num a => a -> a
我将其描述为 a
是 Num
上下文中的类型(如果您认为我错了请纠正我)。
但我不太确定如何描述类似 last
的东西,它具有类型签名:
last :: [a] -> a
我的猜测是说它不是特定于类型的,它接受一个列表并生成与该列表类型相同的单个值。这是正确的思考方式吗?
首先,a
不是 Num
上下文中的 类型,而是 a 类型有一个 Num
个实例。
Num a => a -> a
是constrained多态类型,而[a] -> a
是无约束多态类型,简称多态类型。在不受约束的情况下,a
可以是任何类型;在受约束的情况下,它必须是遵守给定约束的类型。
在 negate
中,您需要对传递的元素进行 操作 ,在您的情况下,您可以对其应用一些运算符,例如(-)
: negate a = -a
.
您不能为 any 类型定义 negate
,因为您需要能够对其调用 (-)
。你需要一些保证给定的参数将是支持此操作的某种类型。
Num
是一种 class 类型,它为您提供了这样的 - 支持 (-)
的编译时保证,以及其他功能,如 +
、*
,也是。您可以在 docs
相比之下,last :: [a] -> a
而不是 (需要)对实际的 a
值做任何事情。它只接受它们和 returns 最后一个。虽然 negate
对 a
值进行操作,但此处 last
对 list 进行操作,但不对其值进行任何操作,它仅传递它们大约。因此,它不需要任何关于它们的知识,因此类型不受约束。
last :: [a] -> a
是 System F 类型
last :: ∀ a. [a] -> a
∀ a
可以理解为一种类型级别的lambda绑定,即在实际值级别列表参数之前,函数接受一个类型级别的参数,告诉列表中包含的元素的类型.此 通用量化 使函数 参数化多态 。
通常情况下,类型变量由类型检查器自动插入。在较新的 GHC Haskell 中,您还可以显式应用它们:
Prelude> :set -XTypeApplications
Prelude> :t last @Int
last @Int :: [Int] -> Int
Prelude> last @Double [5,6,7]
7.0
negate
也是参数多态的,但与 last
不同的是,它并不真正“适用于所有”类型,但仅适用于具有 Num
实例(两者都 Int
和 Double
可以,但不可以,例如 Char
)。换句话说,它不仅接受一个额外的参数指定类型,而且接受一个证明它确实有一个Num
实例。这也将由编译器自动插入。
negate :: ∀ a. Num a => a -> a
Prelude> :t negate @Int
negate @Int :: Int -> Int
Prelude> :t negate @Char
<interactive>:1:1: error:
No instance for (Num Char) arising from a use of ‘negate’