Chapter 10. 持久性携长度数组

我使用携长度数组来表示携带有长度信息的持久数组。给出一个观类型VT,含有 N个类型为VT的携长度数组的类型为arrszref(VT,N)。本质上来讲, 这样的值是类型arrszref(VT,N)size_t(N)的两个 分组的一个装箱类型的对。可以prelude/SATS/arrayref.sats中找到各种用于持 久长度数组的函数接口。

调用下面的函数arrszref_make_arrpszarrszref_make_arrayref就可以创建一个长度数组。

fun{} arrszref_make_arrpsz {a:vt0p}{n:int} (arrpsz (INV(a), n)): arrszref(a) fun{} arrszref_make_arrayref {a:vt0p}{n:int} (arrayref (a, n), size_t(n)): arrszref(a) // end of [arrszref_make_arrayref]

举个例子,下面的代码可以创建一个含有所有十进制数字的长度数组。

val DIGITS = (arrszref)$arrpsz{int}(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

请注意,arrszref是由arrszref_make_arrpsz重载的。

函数模板arrszref_get_atarrszref_set_at可以 分别用来读写一个长度数组,这两个函数模板可以使用如下的接口。

fun{a:t@ype} arrszref_get_at (A: arrszref (a), i: size_t): (a) fun{a:t@ype} arrszref_set_at (A: arrszref (a), i: size_t, x: a): void

给出一个长度数组A,索引i和a,值v,arrszref_get_at(A,i)arrszref_set_at(A, i, v) 可以分别被写作A[i]A[i]:=v。请注意,无论什么时候调用了 arrszref_get_at 或者arrszref_set_at,在运行时 都会检查数组长度是否越界。如果数组越界的情况发生了,就会抛出一个 ArraySubscriptExn的异常。

作为一个简单的例子,下面的代码实现了一个对于给出长度数组解析数组内容的函数。

fun{a:t@ype} arrszref_reverse ( A: arrszref (a) ) : void = let // val n = A.size() val n2 = half (n) // fun loop (i: size_t): void = let in if i < n2 then let val tmp = A[i] val ni = pred(n)-i in A[i] := A[ni]; A[ni] := tmp; loop (succ(i)) end else () // end of [if] end // end of [loop] // in loop (i2sz(0)) end // end of [arrszref_reverse]

在原型实现中,长度数组是一个好选择,因为程序经常需要使用到数组。同样的, 对于那些熟悉相关类型的程序员来说,使用长度数组比数组绝对要好得多。当在 ATS中编程的时候,我经常先使用长度数组,然后用数组替换它们,这样我就清楚 地看到数组长度的好处。

本章代码可在在线代码库中找到。