Answers:
一流的类型启用了一种称为依赖类型的东西。这些允许程序员在类型级别使用类型的值。例如,所有整数对的类型都是常规类型,而左边整数小于右边数字的所有整数对都是从属类型。标准的入门示例是长度编码列表(通常Vector
在Haskell / Idris中称为)。以下伪代码是Idris和Haskell的混合。
-- a natural number
data Nat = Zero | Successor Nat
data Vector length typ where
Empty : Vector Zero typ
(::) : typ -> Vector length typ -> Vector (Successor length) typ
这段代码告诉我们两件事:
cons
将元素添加到列表中会创建一个长度列表 n + 1
这看起来与另一个带有0和的概念非常相似n + 1
,不是吗?我会回到那。
我们从中得到什么?现在,我们可以确定所使用函数的其他属性。例如:的一个重要属性append
是结果列表的长度是两个参数列表的长度之和:
plus : Nat -> Nat -> Nat
plus Zero n = n
plus (Successor m) n = Successor (plus m n)
append : Vector n a -> Vector m a -> Vector (plus n m) a
append Empty ys = ys
append (x::xs) ys = x :: append xs ys
但是所有这些技术似乎在日常编程中似乎都没有用。这与套接字,POST
/ GET
请求等有什么关系?
嗯,事实并非如此(至少不是没有很大的努力)。但这可以通过其他方式帮助我们:
依赖类型使我们能够在代码中表达不变式-规则是函数必须如何表现的规则。使用这些,我们可以提高代码行为的安全性,类似于Eiffel的前提条件和后置条件。这对于自动定理证明非常有用,这是Idris的可能用途之一。
回到上面的示例,长度编码列表的定义类似于归纳的数学概念。在Idris中,您实际上可以在这样的列表上制定归纳的概念,如下所示:
-- If you can supply the following:
list_induction : (Property : Vector len typ -> Type) -> -- a property to show
(Property Empty) -> -- the base case
((w : a) -> (v : Vector n a) ->
Property v -> Property (w :: v)) -> -- the inductive step
(u : Vector m b) -> -- an arbitrary vector
Property u -- the property holds for all vectors
该技术仅限于构造性证明,但功能非常强大。您可以尝试append
归纳写作作为练习。
当然,依赖类型只是头等类型的一种用法,但是可以说它是最常见的一种。其他用途包括,例如,基于函数的参数从函数返回特定类型。
type_func : Vector n a -> Type
type_func Empty = Nat
type_func v = Vector (Successor Zero) Nat
f : (v : Vector n a) -> type_func v
f Empty = 0
f vs = length vs :: Empty
这是一个荒谬的示例,但是它演示了没有一流类型就无法模仿的东西。