14.11.2012 Views

Curry: An Integrated Functional Logic Language

Curry: An Integrated Functional Logic Language

Curry: An Integrated Functional Logic Language

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!