Types 是否可以在OCaml/ReasonML上实现值索引数据类型?
我最近被介绍给agda,这引起了我的注意:Types 是否可以在OCaml/ReasonML上实现值索引数据类型?,types,ocaml,agda,Types,Ocaml,Agda,我最近被介绍给agda,这引起了我的注意: data Vector (A : Set) : Nat → Set where [] : Vector A zero _∷_ : {n : Nat} → A → Vector A n → Vector A (suc n) _++_ : ∀ {a m n} {A : Set a} → Vec A m → Vec A n → Vec A (m + n) [] ++ ys = ys (x ∷ xs) ++ ys = x ∷ (xs +
data Vector (A : Set) : Nat → Set where
[] : Vector A zero
_∷_ : {n : Nat} → A → Vector A n → Vector A (suc n)
_++_ : ∀ {a m n} {A : Set a} → Vec A m → Vec A n → Vec A (m + n)
[] ++ ys = ys
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)
我试图在OCaml中实现这种数组,但我意识到我不能将类型索引到值上。我设法对长度使用类型,但我不能强制执行连接检查Vec A m→ 维卡→ 向量A m+n
是否可行?OCaml不支持依赖类型,因此不可能有值索引类型。然而,对于长度索引列表,仅使用GADT就可以获得相当大的收益 起点是定义一个类型构造来表示succ运算符 然后给出了Peano自然数的经典定义
type ('x,'x_plus_n) nat =
| Zero: ('n, 'n) nat (* n + 0 = n *)
| Succ: ('x,'x_plus_n) nat -> ('x, 'x_plus_n succ) nat
(* succ ( n + x ) = n + succ x *)
let zero = Zero
let one = Succ zero
这种表示法的优点是,可以通过声明将x+y添加到n可以分解为n+x+y来定义加法:
从这些定义中,定义长度索引列表只是将此自然整数编码存储在列表类型中的问题:
type ('elt,'x,'x_plus_length) nlist =
| []: ('elt, 'n,'n) nlist
| (::) : 'elt * ('elt, 'n, 'n_plus_length) nlist
-> ('elt, 'n,'n_plus_length succ) nlist
我们在这里使用的事实是::是一个中缀类型构造函数
[1;2;3]只是1::2::3::[]的一些语法糖
这意味着我们可以写作
let l = [1;2;3]
let l' = [1;2]
l=l'失败,并出现类型错误
使用此定义,只需使用
let rec len: type inf sup. ('elt, inf,sup) nlist -> (inf,sup) nat =
function
| [] -> Zero
| _ :: q -> Succ (len q)
将两个列表连在一起只需要一点技巧就可以确定类型参数的顺序:
let rec (@): type inf mid sup.
('elt,mid,sup) nlist -> ('elt,inf,mid) nlist -> ('elt, inf,sup) nlist =
fun left right -> match left with
| [] -> right
| a :: q -> a :: (q @ right)
事实上,使用这些类型的列表的主要障碍是值限制,这使得保持所有涉及泛型的类型变量而不是弱多态性非常困难。OCaml不支持依赖类型,因此不可能有值索引类型。然而,对于长度索引列表,仅使用GADT就可以获得相当大的收益 起点是定义一个类型构造来表示succ运算符 然后给出了Peano自然数的经典定义
type ('x,'x_plus_n) nat =
| Zero: ('n, 'n) nat (* n + 0 = n *)
| Succ: ('x,'x_plus_n) nat -> ('x, 'x_plus_n succ) nat
(* succ ( n + x ) = n + succ x *)
let zero = Zero
let one = Succ zero
这种表示法的优点是,可以通过声明将x+y添加到n可以分解为n+x+y来定义加法:
从这些定义中,定义长度索引列表只是将此自然整数编码存储在列表类型中的问题:
type ('elt,'x,'x_plus_length) nlist =
| []: ('elt, 'n,'n) nlist
| (::) : 'elt * ('elt, 'n, 'n_plus_length) nlist
-> ('elt, 'n,'n_plus_length succ) nlist
我们在这里使用的事实是::是一个中缀类型构造函数
[1;2;3]只是1::2::3::[]的一些语法糖
这意味着我们可以写作
let l = [1;2;3]
let l' = [1;2]
l=l'失败,并出现类型错误
使用此定义,只需使用
let rec len: type inf sup. ('elt, inf,sup) nlist -> (inf,sup) nat =
function
| [] -> Zero
| _ :: q -> Succ (len q)
将两个列表连在一起只需要一点技巧就可以确定类型参数的顺序:
let rec (@): type inf mid sup.
('elt,mid,sup) nlist -> ('elt,inf,mid) nlist -> ('elt, inf,sup) nlist =
fun left right -> match left with
| [] -> right
| a :: q -> a :: (q @ right)
事实上,使用这些类型的列表的主要障碍是值限制,这使得保持所有涉及泛型的类型变量而不是弱多态性非常困难