Haskell 类型签名和 composite/multi-param 类型构造函数

Haskell type signature with composite/multi-param type constructors

我发现了这些类型的签名:

x :: a b -> Int
x f = 3

y :: a b c -> Int
y f = 3

z :: a b c d -> Int
z f = 3

> x [1] -- 3
> y (1, 2) -- 3
> z (1, 2, 3) -- 3

基本上:

  1. x 只接受包含 1 个或更多参数的类型构造函数的值。
  2. y 只接受包含 2 个或更多参数的类型构造函数的值。
  3. z 只接受包含 3 个或更多参数的类型构造函数的值。

它们是有效的,但我不确定它们的含义或用途。

它们似乎与类型构造函数上的多类型概念或多态性有关,但基于类型构造函数接受的许多参数强制执行不变量。

如果没有进一步的限制,这样的类型是无用的——你真的无法用它们做任何事情,期望将它们传递下去。但这实际上与签名 a -> Int 的情况相同:如果对 a 一无所知,您也无能为力!

但是,例如toInteger :: Integral a => a -> Integer,向参数添加约束允许您做一些事情。例如,

import Data.Foldable
import Prelude hiding (foldr)

x' :: (Foldable a, Integral b) => a b -> Integer
x' = foldr ((+) . toInteger) 0

通常情况下,当你有一个 a b ... n o p q 形式的类型时,那么 a b ... p 至少是 Functor class 的一个实例,通常还有 ApplicativeMonad;有时 FoldableTraversableComonad;有时 a b ... o 将是 Arrow...这些约束允许您对复合类型做很多事情,而无需知道您正在处理的特定类型构造函数。

在研究了@leftaroundabout 的答案并在 GHCI 中进行了实验之后,我开始理解复合类型。它们与应用类型的统一基于评估顺序和它们的类型变量的种类签名。评估顺序非常重要,因为 a b c ~ (((a) b) c)a (b c)(a ((b) c)。这使得 a b c 匹配复合类型,其中 a 与类型构造函数 * -> * -> * 匹配,a b* -> *a b c*.

我在这个要点中用图表和 GHCI 代码对其进行了完整的解释 (https://gist.github.com/CMCDragonkai/2a1d3ecb67dcdabfc7e0)(堆栈溢出太长了)