A datasort is rather similar to a dataype. However, the former is
declared in the statics of ATS while the latter in the dynamics of ATS. To
see a typical need for datasorts, let us try to encode a theorem in ATS
stating that s is strictly less than 2h if s and
h are the size and height, respectively, of a given binary tree. To
represent binary trees in the statics, we first declare a datasort as
follows:
The name of the declared datasort is
tree and there are two
constructor associated with it: E and B, where E forms the empty tree and B
forms a tree by joining two given trees. For instance, B(E(), E()) is a
static term of the sort
tree that represents a singleton tree,
that is, a tree consisting of exactly one node. Please note that the trees formed
by E and B are really just tree skeletons carrying no data.
We now declare two dataprops as follows for capturing the notion of
size and height of trees:
Given a tree t and an integer s, SZ(t, s) encodes the relation that the
size of t equals s. Similiarly, given a tree t and an integer h, HZ(t, h)
encodes the relation that the height of t equals h.
As the power function (of base 2) is not available in the statics of ATS,
we declare a dataprop as follows to capture it:
Given two integers h and p, POW2 (h, p) encodes the relation that
2
h equals p.
It should be clear by now that the following proof function
interface encodes the theorem stating that s is strictly less than
2h if s and h are the size and height of a
given binary tree:
Let us now construct an implementation of this proof function as follows.
We first establish some elementary properties on the power function
(of base 2):
Clearly,
pow2_istot shows that the relation encoded by the
dataprop
POW2 is a total relation;
pow2_pos
proves that the power of each natural number is positive;
pow2_inc establishes that the power function is increasing.
The function lemma_tree_size_height can be implemented
as follows:
The inner function
lemma, which is given a termination metric
consisting of a static term of the sort
tree, corresponds to a
proof based on structural induction (where the involved structure is the
binary tree
t). Given two terms t1 and t2 of the sort
tree, t1 is (strictly) less than t2 if t1 is a (proper)
substructure of t2. Evidently, this is a well-founded ordering. The
keyword
scase is used to form a dynamic expression that does
case-analysis on a static term (built by constructors associated with some
declared datasort). So the relation between
sif and
scase
is essentially parallel to that between
if and
case.
Please find the entirety of the above code
on-line.