Curry: An Integrated Functional Logic Language
Curry: An Integrated Functional Logic Language
Curry: An Integrated Functional Logic Language
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
A single computation step performs a reduction in exactly one unsolved expression of a disjunction.<br />
To provide a precise definition of the operational semantics, we use definitional trees. 18<br />
A definitional tree is a hierarchical structure containing all rules of a defined function. T is a<br />
definitional tree with call pattern π iff the depth of T is finite and one of the following cases holds:<br />
T = rule(l = r), where l = r is a variant of a rule such that l = π.<br />
T = branch(π, o, r, T1, . . . , Tk), where o is an occurrence of a variable in π, r ∈ {rigid, flex},<br />
c1, . . . , ck are different constructors of the sort of π|o, for some k > 0, and, for all i = 1, . . . , k,<br />
Ti is a definitional tree with call pattern π[ci(x1, . . . , xn)]o, where n is the arity of ci and<br />
x1, . . . , xn are new variables.<br />
T = or(T1, T2), where T1 and T2 are definitional trees with call pattern π. 19<br />
A definitional tree of an n-ary function f is a definitional tree T with call pattern f(x1, . . . , xn),<br />
where x1, . . . , xn are distinct variables, such that for each rule l = r with l = f(t1, . . . , tn) there is a<br />
node rule(l ′ = r ′ ) in T with l variant of l ′ . In the following, we write pat(T ) for the call pattern of<br />
a definitional tree T .<br />
It is always possible to construct a definitional tree for each function (concrete algorithms are<br />
described in [3, 33] and in Section D.6). For instance, consider the following definition of the<br />
less-or-equal predicate on natural numbers represented by data terms built from z (zero) and s<br />
(successor):<br />
data Nat = z | s Nat<br />
leq :: Nat -> Nat -> Bool<br />
leq z n = True<br />
leq (s m) z = False<br />
leq (s m) (s n) = leq m n<br />
Consider a function call like (leq e1 e2). In order to apply some reduction rule, the first argument<br />
e1 must always be evaluated to head normal form (i.e., to an expression without a defined function<br />
symbol at the top). However, the second argument must be evaluated only if the first argument<br />
has the form (s e). 20 This dependency between the first and the second argument is expressed by<br />
the definitional tree<br />
branch(leq(x1, x2), 1, flex, rule(leq(z, x2) = True),<br />
branch(leq(s(x), x2), 2, flex, rule(leq(s(x), z) = False),<br />
rule(leq(s(x), s(y)) = leq(x, y))))<br />
This definitional tree specifies that the first argument is initially evaluated and the second argument<br />
is only evaluated if the first argument has the constructor s at the top. The precise operational<br />
meaning induced by definitional trees is described in the following section.<br />
18<br />
Our notion is influenced by <strong>An</strong>toy’s work [3], but here we use an extended form of definitional trees.<br />
19<br />
For the sake of simplicity, we consider only binary or nodes. The extension to such nodes with more than two<br />
subtrees is straightforward.<br />
20<br />
Naive lazy narrowing strategies may also evaluate the second argument in any case. However, as shown in [6],<br />
the consideration of dependencies between arguments is essential to obtain optimal evaluation strategies.<br />
65