Higher-Order Narrowing with Definitional Trees

Michael Hanus^{1} and Christian Prehofer^{2}

1 Informatik II, RWTH Aachen, D-52056 Aachen, Germany

                      hanus@informatik.rwth-aachen.de

2 Fakultät für Informatik, TU München, D-80290 München, Germany

                     prehofer@informatik.tu-muenchen.de

In Proc. Seventh Intern. Conference on Rewriting Techniques and Applications (RTA’96), New Brunswick (USA), Springer LNCS 1103, pp. 138–152, 1996

Abstract. Functional logic languages with a sound and complete operational semantics are mainly based on narrowing. Due to the huge search space of simple narrowing, steadily improved narrowing strategies have been developed in the past. Needed narrowing is currently the best narrowing strategy for first-order functional logic programs due to its optimality properties w.r.t. the length of derivations and the number of computed solutions. In this paper, we extend the needed narrowing strategy to higher-order functions and λ-terms as data structures. By the use of definitional trees, our strategy computes only incomparable solutions. Thus, it is the first calculus for higher-order functional logic programming which provides for such an optimality result. Since we allow higher-order logical variables denoting λ-terms, applications go beyond current functional and logic programming languages.

1 Introduction

Functional logic languages [7] with a sound and complete operational semantics are mainly based on narrowing. Narrowing, originally introduced in automated theorem proving [20], is used to solve goals by finding appropriate values for variables occurring in arguments of functions. A narrowing step instantiates variables in a goal and applies a reduction step to a redex of the instantiated goal. The instantiation of goal variables is usually computed by unifying a subterm of the goal with the left-hand side of some rule.

Example 1. Consider the following rules defining the less-or-equal predicate on natural numbers which are represented by terms built from 0 and s:

0 ≤ X → true
s(X) ≤ 0 → false
s(X) ≤ s(Y) → X ≤ Y

To solve the goal s(X) ≤ Y, we perform a first narrowing step by instantiating Y to s(Y_{1}) and applying the third rule, and a second narrowing step by instantiating X to 0 and applying the first rule:

s(X) ≤ Y ⇝_{{Y ↦s(Y_{1})}} X ≤ Y_{1} ⇝_{{X↦0}} true

Since the goal is reduced to true, the computed solution is {X ↦ 0, Y ↦ s(Y_{1})}.

Due to the huge search space of simple narrowing, steadily improved narrowing strategies have been developed in the past. Needed narrowing [2] is based on the idea to evaluate only subterms which are needed in order to compute some result. For instance, in a goal t_{1} ≤ t_{2}, it is always necessary to evaluate t_{1} (to some head normal form) since all three rules in Example 1 have a non-variable first argument. On the other hand, the evaluation of t_{2} is only needed if t_{1} is of the form s(⋯). Thus, if t_{1} is a free variable, needed narrowing instantiates it to a constructor, here 0 or s. Depending on this instantiation, either the first rule is applied or the second argument t_{2} is evaluated. Needed narrowing is the currently best narrowing strategy for first-order functional logic programs due to its optimality properties w.r.t. the length of derivations and the number of computed solutions [2]. Moreover, it can be efficiently implemented by pattern-matching and unification due to its local computation of a narrowing step (see, e.g., [8]).

In this paper, we extend the needed narrowing strategy to higher-order functions and λ-terms as data structures. We introduce a class of higher-order inductively sequential rewrite rules which can be defined via definitional trees. Although this class is a restriction of general higher-order rewrite systems, it covers higher-order functional languages. As higher-order rewrite steps can be expensive in general, we show that finding a redex with inductively sequential rules can be performed as in the first-order case.

Since our narrowing calculus LNT is oriented towards previous work on higherorder narrowing [19], we show in the first part that LNT coincides with needed narrowing in the first-order case. For the higher-order case, we show soundness and completeness with respect to higher-order needed reductions, which we define via definitional trees. Furthermore, we show that the calculus is optimal w.r.t. the solutions computed, i.e., no solution is produced twice. Optimality of higher-order reductions is subject of current research. It is however shown that higher-order needed reductions are in fact needed for reduction to a constructor normal form.

This strategy is the first calculus for higher-order functional logic programming which provides for optimality results. Moreover, it falls back to the optimal needed narrowing strategy if the higher-order features are not used, i.e., our calculus is a conservative extension of an optimal first-order narrowing calculus. Since we allow higher-order logical variables denoting λ-terms, applications go beyond current functional and logic programming languages. In general, our calculus can compute solutions for variables of functional type. Although this is very powerful, we show that the incurring higher-order unification can sometimes be avoided by techniques similar to [4]. Due to lack of space, some details and the proofs are omitted. They can be found in [9].

2 Preliminaries

We briefly introduce the simply typed λ-calculus (see e.g. [10]). We assume the following variable conventions:

– F, G, H, P, X, Y denote free variables,

– a, b, c, f, g (function) constants, and – x, y, z bound variables.

Type judgments are written as t : τ. Further, we often use s and t for terms and u, v, w for constants or bound variables. The set of types T for the simply typed λ-terms is generated by a set T_{0} of base types (e.g., int, bool) and the function type constructor →. The syntax for λ-terms is given by

t = F | x | c | λx.t | (t_{1} t_{2})

A list of syntactic objects s_{1}, …, s_{n} where n ≥ 0 is abbreviated by \overline{s_{n}}. For instance, n-fold abstraction and application are written as λ\overline{x_{n}}.s = λx_{1} … λx_{n}.s and a(\overline{s_{n}}) = ((⋯ (a s_{1}) ⋯) s_{n}), respectively. Substitutions are finite mappings from variables to terms, denoted by \{\overline{X_{n} ↦ t_{n}}\}, and extend homomorphically from variables to terms. Free and bound variables of a term t will be denoted as FV(t) and BV(t), respectively. A term t is ground if FV(t) = {}. The conversions in λ-calculus are defined as:

– α-conversion: λx.t =_{α} λy.({x ↦ y}t),

– β-conversion: (λx.s)t =_{β} {x ↦ t}s, and

– η-conversion: if x ∉ FV(t), then λx.(tx) =_{η} t.

The long βη-normal form [14] of a term t, denoted by t↕_{β}^{η}, is the η-expanded form of the β-normal form of t. It is well known [10] that s =_{αβη} t iff s↕_{β}^{η} =_{α} t↕_{β}^{η}. As long βη-normal forms exist for typed λ-terms, we will in general assume that terms are in long βη-normal form. For brevity, we may write variables in η-normal form, e.g., X instead of λ\overline{x_{n}}.X(\overline{x_{n}}). We assume that the transformation into long βη-normal form is an implicit operation, e.g., when applying a substitution to a term.

A substitution θ is in long βη-normal form if all terms in the image of θ are in long βη-normal form. The convention that α-equivalent terms are identified and that free and bound variables are kept disjoint (see also [5]) is used in the following. Furthermore, we assume that bound variables with different binders have different names. Define Dom(θ) = {X | θX ≠ X} and Rng(θ) = ⋃_{X∈Dom(θ)} FV(θX). Two substitutions are equal on a set of variables W, written as θ =_{W} θ′, if θα = θ′α for all α ∈ W. The restriction of a substitution to a set of variables W is defined as θ_{|W} α = θα if α ∈ W and θ_{|W} α = α otherwise. A substitution θ is idempotent iff θ = θθ. We will in general assume that substitutions are idempotent. A substitution θ′ is more general than θ, written as θ′ ≤ θ, if θ = σθ′ for some substitution σ. We describe positions in λ-terms by sequences over natural numbers. The subterm at a position p in a λ-term t is denoted by t|_{p}. A term t with the subterm at position p replaced by s is written as t[s]_{p}.

A term t in β-normal form is called a higher-order pattern if every free occurrence of a variable F is in a subterm F (\overline{u_{n}}) of t such that the \overline{u_{n}} are η-equivalent to a list of distinct bound variables. Unification of patterns is decidable and a most general unifier exists if they are unifiable [12]. Examples are λx, y.F (x, y) and λx.f(G(λz.x(z))).

A rewrite rule [14] is a pair l → r such that l is a higher-order pattern but not a free variable, l and r are long βη-normal forms of the same base type, and FV(l) ⊇ FV(r). Assuming a rule l → r and a position p in a term s in long βη-normal form, a rewrite step from s to t is defined as

s ⟶_{p,θ}^{l→r} t ⇔ s|_{p} = θl ∧ t = s[θr]_{p}.

For a rewrite step we often omit some of the parameters l → r, p and θ. It is a standard assumption in functional logic programming that constant symbols are divided into free constructor symbols and defined symbols. A symbol f is called a defined symbol or operation, if a rule f(⋯) → t exists. A constructor term is a term without defined symbols. Constructor symbols and constructor terms are denoted by c and d. A term f(\overline{t_{n}}) is called operation-rooted (respectively constructor-rooted) if f is a defined symbol (respectively constructor). A higher-order rewrite system (HRS) R is a set of rewrite rules. A term is in R-normal form if no rule from R applies and a substitution θ is R-normalized if all terms in the image of θ are in R-normal form.

By applying rewrite steps, we can compute the value of a functional expression. However, in the presence of free variables, we have to compute values for these free variables such that the instantiated expression is reducible. This is the motivation for narrowing which will be precisely defined in the following sections. Narrowing is intended to solve goals, where a goal is an expression of Boolean type that should be reduced to the constant true. This is general enough to cover the equation solving capabilities of current functional logic languages with a lazy operational semantics, like BABEL [13] or K-LEAF [6], since the strict equality ≈^{1} can be defined as a binary operation by a set of orthogonal rewrite rules (see [2, 6, 13] for more details about strict equality). An important consequence of this restriction on goals is the fact that during the successful rewriting of a goal the topmost symbol is always an operation or the constant true. This property will be used to simplify the narrowing calculus.

Notice that a subterm s|_{p} may contain free variables which used to be bound in s. For rewriting it is possible to ignore this, as only matching of a left-hand side of a rewrite rule is needed. For narrowing, we need unification and hence we use the following construction to lift a rule into a binding context to facilitate the technical treatment. An \overline{x_{k}}-lifter of a term t away from W is a substitution σ = \{F ↦ (ρF)(\overline{x_{k}}) | F ∈ FV(t)\} where ρ is a renaming such that Dom(ρ) = FV(t), Rng(ρ) ∩ W = {} and ρF : τ_{1} → ⋯ → τ_{k} → τ if x_{1} : τ_{1}, …, x_{k} : τ_{k} and F : τ. A term t (rewrite rule l → r) is \overline{x_{k}}-lifted if an \overline{x_{k}}-lifter has been applied to t (l and r). For example, {G ↦ G′(x)} is an x-lifter of g(G) away from any W not containing G′.

3 First-Order Definitional Trees

Definitional trees are introduced in [1] to define efficient normalization strategies for (first-order) term rewriting. The idea is to represent all rules for a defined

1 The strict equality t ≈ t′ holds if t and t′ are reducible to the same ground constructor term. Note that normal forms may not exist in general due to non-terminating rewrite rules.

symbol in a tree and to control the selection of the next redex by this tree. This technique is extended to narrowing in [2]. We will extend definitional trees to the higher-order case in order to obtain a similar strategy for higher-order narrowing. To state a clear relationship between the first-order and the higher-order case, we review the first-order case in this section and present the needed narrowing calculus in a new form. Thus, we assume in this section that all terms are first-order, i.e., λ-abstractions and functional variables do not occur.

Traditionally [7], a term t is narrowed into a term t′ if there exist a nonvariable position p in t (i.e., t|_{p} is not a free variable), a variant l → r of a rewrite rule with FV(t) ∩ FV(l → r) = {} and a most general unifier σ of t|_{p} and l such that t = σ(t[r]_{p}). In this case we write t ⇝_{σ} t′. We write t_{0} ⇝_{σ}^{∗} t_{n} if there is a narrowing derivation t_{0} ⇝_{σ_{1}} t_{1} ⇝_{σ_{2}} ⋯ ⇝_{σ_{n}} t_{n} with σ = σ_{n} ⋯ σ_{2}σ_{1}. In order to compute all solutions by narrowing, we have to apply all rules at all non-variable subterms in parallel. Since this simple method leads to a huge and often infinite search space, many improvements have been proposed in the past (see [7] for a survey). A narrowing strategy determines the position where the next narrowing step should be applied. As shown in [2], an optimal narrowing strategy can be obtained by dropping the requirement for most general unifiers and controlling the instantiation of variables and selection of narrowing positions by a data structure, called definitional tree. T is a definitional tree with pattern π iff its depth is finite and one of the following cases holds:

T = rule(l → r), where l → r is a variant of a rule in R such that l = π. T = branch(π, o, \overline{T_{k}}), where o is an occurrence of a variable in π, \overline{c_{k}} are different

constructors of the type of π|_{o} (k > 0), and, for i = 1, …, k, T_{i} is a definitional tree with pattern π[c_{i}(\overline{X_{n_{i}}})]_{o}, where n_{i} is the arity of c_{i} and \overline{X_{n_{i}}} are new distinct variables.

A definitional tree of an n-ary function f is a definitional tree T with pattern f(\overline{X_{n}}), where \overline{X_{n}} are distinct variables, such that for each rule l → r with l = f(\overline{t_{n}}) there is a node rule(l′ → r′) in T with l variant of l′.^{2} For instance, the rules in Example 1 can be represented by the following definitional tree:

branch(X ≤ Y, 1, rule(0 ≤ Y → true),
branch(s(X′) ≤ Y, 2, rule(s(X′) ≤ 0 → false),
rule(s(X′) ≤ s(Y′) → X′ ≤ Y′)))

A definitional tree starts always with the most general pattern for a defined symbol and branches on the instantiation of a variable to constructor-headed terms, here 0 and s(X′). It is essential that each rewrite rule occurs only once as a leaf of the tree. Thus, when evaluating the arguments of a term f(\overline{t_{n}}) to constructor terms, the tree can be incrementally traversed to find the matching rule.

A function f is called inductively sequential if there exists a definitional tree of f such that each rule node corresponds to exactly one rule of the rewrite system R. The term rewriting system R is called inductively sequential if each function defined by R is inductively sequential.

2 This corresponds to Antoy’s notion [1] except that we ignore exempt nodes.

A definitional tree defines a strategy to apply narrowing steps.^{3} To narrow a term t, we consider the definitional tree T of the outermost function symbol of t (note that, by our restriction on goals, the outermost symbol is always a Boolean function). If T = rule(l → r), we apply the rule l → r to t. If T = branch(π, o, \overline{T_{k}}), we consider the subterm t|_{o}. If t|_{o} has a function symbol at the top, we narrow this subterm (to a head normal form) by recursively applying our strategy to t|_{o}. If t|_{o} has a constructor symbol at the top, we narrow t with T_{j}, where the pattern of T_{j} unifies with t. If t|_{o} is a variable, we non-deterministically select a subtree T_{j}, instantiate t|_{o} to the constructor of the pattern of T_{j} at position o, and narrow this instance of t with T_{j}. This strategy is called needed narrowing [2] and is the currently best narrowing strategy due to its optimality w.r.t. the length of derivations (if terms are shared) and the number of computed solutions.

In order to extend this strategy to higher-order functions, another representation is required since it is shown in [17] that the direct application of narrowing steps to inner subterms should be avoided in the presence of λ-bound variables. For this purpose we transform the needed narrowing calculus into a lazy narrowing calculus in the spirit of Martelli/Montanari’s inference rules. In a first step, we integrate the definitional trees into the rewrite rules by extending the language of terms and providing case constructs to express the concrete narrowing strategy. A case expression has the form

case X of c_{1}(\overline{X_{n_{1}}}) : X_{1}, …, c_{k}(\overline{X_{n_{k}}}) : X_{k}

where X is a variable, c_{1}, …, c_{k} are different constructors of the type of X, and X_{1}, …, X_{k} are terms possibly containing case expressions. Using such case expressions, each inductively sequential function symbol can be defined by exactly one rewrite rule. For instance, the rules for the function ≤ defined in Example 1 are represented by the following rule:

X ≤ Y → case X of 0 : true, s(X_{1}) : (case Y of 0 : false, s(Y_{1}) : X_{1} ≤ Y_{1})

To be more precise, we translate a definitional tree T into a term with case expressions by the use of the function dtc(T ) which is defined as follows:

dtc(rule(l → r))  = r
dtc(branch(π, o, \overline{T_{k}})) = case π|_{o} of π_{1}|_{o} : dtc(T_{1}), …, π_{k}|_{o} : dtc(T_{k})
where π_{i} is the pattern of T_{i}

If T is the definitional tree with pattern f(\overline{X_{n}}) of the n-ary function f, then f(\overline{X_{n}}) → dtc(T ) is the new rewrite rule for f. A case expression case X of \overline{p_{n} : X_{n}} can be considered as a function with arity 2n + 1 where the semantics is defined by the following n rewrite rules:^{4}

case p_{i} of \overline{p_{n} : X_{n}} → X_{i} (i = 1, …, n)

3 Due to lack of space, we omit a precise definition which can be found in [2]. 4 To be more precise, different case functions are needed for case expressions with differ-

ent patterns, i.e., the case functions should be indexed by the case patterns. However, for the sake of readability, we do not write these indices and allow the overloading of the case function symbols.

Bind

e →^{?} Z, G ⇒^{σ} σ(G)

if e is not a case term and σ = {Z ↦ e}

Case Select

case c(\overline{t_{n}}) of \overline{p_{k} : X_{k}} →^{?} Z, G ⇒^{σ} σ(X_{i}) →^{?} Z, G
where p_{i} = c(\overline{X_{n}}) and σ = \{\overline{X_{n} ↦ t_{n}}\}

Case Guess

case X of \overline{p_{k} : X_{k}} →^{?} Z, G ⇒^{σ} σ(X_{i}) →^{?} Z, σ(G)
where σ = {X ↦ p_{i}}

Case Eval

case f(\overline{t_{n}}) of \overline{p_{k} : X_{k}} →^{?} Z, G ⇒^{σ} σ(X) →^{?} X, case X of \overline{p_{k} : X_{k}} →^{?} Z, G
if f(\overline{X_{n}}) → X ∈ R′ is a rule with fresh variables,
σ = \{\overline{X_{n} ↦ t_{n}}\}, and X is a fresh variable

Fig. 1. Calculus LNT for lazy narrowing with definitional trees in the first-order case

In the following, we denote by R an inductively sequential rewrite system, by R′ its translated version containing exactly one rewrite rule for each function defined by R, and by R_{c} the additional case rewrite rules. The following theorem states that needed narrowing w.r.t. R and leftmost-outermost narrowing w.r.t. R′ ∪ R_{c} are equivalent, where leftmost-outermost means that the selected subterm is the leftmost-outermost one among all possible narrowing positions.^{5}

Theorem 1. Let t be a term with a Boolean function at the top. For each needed narrowing derivation t ⇝_{σ}^{∗} true w.r.t. R there exists a leftmost-outermost narrowing derivation t ⇝_{σ′}^{∗} true w.r.t. R′ ∪ R_{c} with σ =_{FV(t)} σ′, and vice versa.

As mentioned above, in the higher-order case we need a narrowing calculus which always applies narrowing steps to the outermost function symbol which is often different from the leftmost-outermost narrowing position. For this purpose, we transform a leftmost-outermost narrowing derivation w.r.t. R′ ∪ R_{c} into a derivation on a goal system G (a sequence of goals of the form t →^{?} X) where narrowing rules are only applied to the outermost function symbol of the leftmost goal. This is the purpose of the inference system LNT shown in Figure 1. The Bind rule propagates a term to the subsequent case expression. The Case rules correspond to the case distinction in the definition of needed narrowing, where the narrowing of a function is integrated in the Case Eval rule. Note that the only possible non-determinism during computation with these inference rules is in the Case Guess rule. Since we are interested in solving goals by reduction to true, we assume that the initial goal has always the form case t of true : true →^{?} T. We use this representation in order to provide a calculus with few inference rules. Note that T ↦ true if such a goal can be reduced to the empty goal system.

5 A position p is leftmost-outermost in a set P of positions if there is no p′ ∈ P with p′ prefix of p, or p′ = q · i · q′ and p = q · j · q′′ and i < j.

Theorem 2. Let t be a term with a Boolean function at the top and X a fresh variable. For each leftmost-outermost narrowing derivation t ⇝_{σ}^{∗} true w.r.t. R′ ∪

R_{c} there exists a LNT-derivation case t of true : true →^{?} X ⇒^{∗}^{σ′} true →^{?} X

w.r.t. R′ such that σ′ =_{FV(t)} σ, and vice versa.

Theorems 1 and 2 imply the equivalence of needed narrowing and the calculus LNT. Since we will extend LNT to higher-order functions in the next section, the results in this section show that our higher-order calculus is a conservative extension of an optimal first-order narrowing strategy.

4 Higher-Order Definitional Trees

In the following we extend first-order definitional trees to the higher-order case. To generalize from the first-order case, it is useful to recall the main ideas: When evaluating the arguments of a term f(\overline{t_{n}}) to constructor terms, the definitional tree can be incrementally traversed to find the (single) matching rule. It is essential that each branching depends on only one subterm (or argument to the function) and that for each rigid term (non-variable headed), a single branch can be chosen. For this purpose, we need further restrictions in the higher-order case, where we employ λ-terms as data structure, e.g., higher-order terms with bound variables in the left-hand sides. For instance, we permit the rules

diff(λy.y, X)  → 1
diff(λy.sin(F (y)), X) → cos(F (X)) ∗ diff(λy.F (y), X)
diff(λy.ln(F (y)), X) → diff(λy.F (y), X)/F (X)

where diff(F, X) computes the differential of F at X.

A shallow pattern is a linear term of the form λ\overline{x_{n}}.v(\overline{H_{m}(\overline{x_{n}})}). We will use shallow patterns for branching in trees. In contrast to the first-order case, v can also be a bound variable.

Definition 3. T is a higher-order definitional tree (hdt) iff its depth is finite and one of the following cases holds:

– T = p_{f} : case X of \overline{T_{n}}

– T = p_{f} : rhs,

where p_{f} are shallow patterns with fresh variables, X is a free variable and \overline{T_{n}} are hdts in the first case, and rhs is a term (representing the right-hand side of a rule). Moreover, all shallow patterns of the hdts \overline{T_{n}} must be pairwise non-unifiable.

We write hdts as p_{f} : X, where X stands for a case expression or a term. To simplify technicalities, rewrite rules f(\overline{X_{n}}) → X are identified with the hdt f(\overline{X_{n}}) : X. With this latter form of a rule, we can relate rules to the usual notation as follows. The selector of a tree T of the form T = p_{f} : X is defined as sel(T ) = p_{f}. For a node T′ in a tree T , the constraints in the case expressions on the path to it determine a term, which is recursively defined by the pattern function pat_{T} (T′):

pat_{T} (T′) = \{ \begin{matrix}sel(T′) & if T = T′ (i.e., T′ is the root) \\ \{X ↦ sel(T′)\}pat_{T} (T′′) & if T′ has parent T′′ = p_{f} : case X of \overline{T_{n}} \end{matrix}

Each branch variable must belong to the pattern of this node, i.e., for each node T′ = p_{f} : case X of \overline{T_{n}} in a tree T , X is a free variable of pat_{T} (T′). Furthermore, each leaf T′ = p : rhs of a hdt T is required to correspond to a rewrite rule l → r, i.e., pat_{T} (T′) → rhs is a variant of l → r. T is called hdt of a function f if for all rewrite rules of f there is exactly one corresponding leaf in T .

As in the first-order case, rewrite rules must be constructor based. This means that in a hdt only the outermost pattern has a defined symbol. An HRS, for all of which defined symbols hdts exits, is called inductively sequential.

For instance, the rules for diff above have the hdt

diff(F, X) → case F of λy.y  : 1,
λy.sin(F′(y)) : cos(F′(X)) ∗ diff(λy.F′(y), X),
λy.ln(F′(y)) : diff(λy.F′(y), X)/F′(X)

Note that free variables in left-hand sides must have all bound variables of the current scope as arguments. Such terms are called fully extended. This important restriction, which also occurs in [16], allows to find redices as in the first-order case, and furthermore simplifies narrowing. For instance, Flex-Flex pairs do not arise here, in contrast to the full higher-order case [18, 19]. Consider an example for some non-overlapping rewrite rules which do not have a hdt:

\begin{aligned}f(λx.c(x)) & → & a \\ f(λx.H) & → & b \end{aligned}

The problem is that for rewriting a term with these rules the full term must be scanned. For example, if the argument to f is the rigid term λx.c(G(t)), it is not possible to commit to one of the rules (or branches of a tree) before checking if the bound variable x occurs inside t. In general, this may lead to an unexpected complexity w.r.t. the term size for evaluation via rewriting.

We define the \overline{x_{k}}-lifting of hdts by schematically applying the \overline{x_{k}}-lifter to all terms in the tree, i.e., to all patterns, right-hand sides, and free variables in cases.

5 Narrowing with Higher-Order Definitional Trees

In the higher-order case, the rules of LNT of Section 3 must be extended to account for several new cases. Compared to the first-order case, we need to maintain binding environments and higher-order free variables, possibly with arguments, which are handled by higher-order unification. For this purpose, the Imitation, the Function Guess and the Projection rules have been added in Figure 2. These three new rules, to which we refer as the Guess Rules, are the only ones to compute substitutions for the variables in the case constructs. The Case Guess rule of the first-order case can be retained by applying Imitation plus Case Select. The Imitation and Projection rules are taken from higher-order unification and compute a partial binding for some variable. The Function Guess rule covers the case of non-constructor solutions, which may occur for higher-order variables. It thus enables the synthesis of functions from existing ones. Note that the selection of a binding in this rule is only restricted by the types occurring. For all rules, we assume that newly introduced variables are fresh, as in the first-order case.

Bind

e →^{?} Z, G  ⇒^{{}} σ(G)

where σ = {Z ↦ e} and e is not a case term

Case Select

λ\overline{x_{k}}.case λ\overline{y_{l}}.v(\overline{t_{m}}) of ⇒^{\{\}} λ\overline{x_{k}}.σ(X_{i}) →^{?} Z, G

\overline{p_{n} : X_{n}} →^{?} Z, G if p_{i} = λ\overline{y_{l}}.v(\overline{X_{m}(\overline{x_{k}}, \overline{y_{l}})}) and σ = \{\overline{X_{m} ↦ λ\overline{x_{k}}, \overline{y_{l}}.t_{m}}\}

Imitation

λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{t_{m}}) of ⇒^{σ} σ(λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{t_{m}}) of \overline{p_{n} : X_{n}} →^{?} Z, G)

\overline{p_{n} : X_{n}} →^{?} Z, G if p_{i} = λ\overline{y_{l}}.c(\overline{X_{o}(\overline{x_{k}}, \overline{y_{l}})}) and σ = \{X ↦ λ\overline{x_{m}}.c(\overline{H_{o}(\overline{x_{m}})})\}

Function Guess

λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{t_{m}}) of ⇒^{σ} σ(λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{t_{m}}) of \overline{p_{n} : X_{n}} →^{?} Z, G)

\overline{p_{n} : X_{n}} →^{?} Z, G

if λ\overline{x_{k}}, \overline{y_{l}}.X(\overline{t_{m}}) is not a higher-order pattern,
σ = \{X ↦ λ\overline{x_{m}}.f(\overline{H_{o}(\overline{x_{m}})})\}, and f is a defined function

Projection

λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{t_{m}}) of ⇒^{σ} σ(λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{t_{m}}) of \overline{p_{n} : X_{n}} →^{?} Z, G)

\overline{p_{n} : X_{n}} →^{?} Z, G where σ = \{X ↦ λ\overline{x_{m}}.x_{i}(\overline{H_{o}(\overline{x_{m}})})\}

Case Eval

λ\overline{x_{k}}.case λ\overline{y_{l}}.f(\overline{t_{m}}) of ⇒^{\{\}} λ\overline{x_{k}}, \overline{y_{l}}.σ(X) →^{?} X,
\overline{p_{n} : X_{n}} →^{?} Z, G  λ\overline{x_{k}}.case λ\overline{y_{l}}.X(\overline{x_{k}}, \overline{y_{l}}) of \overline{p_{n} : X_{n}} →^{?} Z, G
where σ = \{\overline{X_{m} ↦ λ\overline{x_{k}}, \overline{y_{l}}.t_{m}}\}, and
f(\overline{X_{m}(\overline{x_{k}}, \overline{y_{l}})}) → X is a \overline{x_{k}}, \overline{y_{l}}-lifted rule

Fig. 2. System LNT for needed narrowing in the higher-order case

Notice that for goals where only higher-order patterns occur, there is no choice between Projection and Imitation and furthermore Function Guess does not apply. This special case is refined later in Section 8.

For a sequence ⇒^{θ_{1}} ⋯ ⇒^{θ_{n}} of LNT steps, we write ⇒^{∗}^{θ}, where θ = θ_{n} ⋯ θ_{1}. In contrast to the calculus in Section 3 not all substitutions are recorded for ⇒^{∗}; only the ones produced by guessing are needed for the technical treatment. Informally, all other substitutions only concern intermediate (or auxiliary) variables similar to [18].

As in the first-order case, we consider only reductions to the dedicated constant true. This is general enough to cover reductions to a term without defined symbols c, since a reduction t ⟶^{∗} c can be modeled by f(t) ⟶^{∗} true with the additional rule f(c) → true and a new symbol f. Hence we assume that solving a goal t →^{?} true is initiated with the initial goal I(t) = case t of true : true →^{?} X.

As an example, consider the goal λx.diff(λy.sin(F (x, y)), x) →^{?} λx.cos(x) w.r.t. the rules for diff and the hdt for the function ∗:

X ∗ Y → case Y of 1 : X, s(Y′) : X + X ∗ Y′

To solve the above goal, we simply add the rule f(λx.cos(x)) → true to solve the following goal. Since each computation step only affects the two leftmost goals, we often omit the others.

case f(λx.diff(λy.sin(F (x, y)), x)) of true : true →^{?} X_{1}

⇒_{Case Eval}

case λx.diff(λy.sin(F (x, y)), x) of cos : true →^{?} X_{2},

case X_{2} of true : true →^{?} X_{1}

⇒_{Case Eval} λx.case λy.sin(F (x, y)) of …, λy.sin(G(x, y)) : …, … →^{?} X_{3},

case X_{3} of cos : true →^{?} X_{2}, case X_{2} of true : true →^{?} X_{1}

⇒_{Case Select} λx.cos(F (x, x)) ∗ diff(λy.F (x, y), x) →^{?} X_{3}, case X_{3} of cos : true →^{?} X_{2}, …

⇒_{Bind} case λx.cos(F (x, x)) ∗ diff(λy.F (x, y), x) of cos : true →^{?} X_{2}, …

⇒_{Case Eval} λx.case diff(λy.F (x, y), x) of 1 : cos(F (x, x)), … →^{?} X′_{3}, …

⇒_{Case Eval} λx.case λy.F (x, y) of λy.y : 1, … →^{?} X_{4}, λx.case X_{4}(x) of 1 : cos(F (x, x)), …

⇒_{P rojection}^{{F ↦λx,y.y}} λx.case λy.y of λy.y : 1, … →^{?} X_{4}, λx.case X_{4}(x) of 1 : cos(x), … →^{?} X′_{3}, …

⇒_{Case Select} λx.1 →^{?} X_{4}, λx.case X_{4}(x) of 1 : cos(x), … →^{?} X′_{3}, …

⇒_{Bind} λx.case 1 of 1 : cos(x), … →^{?} X′_{3}, case X′_{3} of cos : true →^{?} X_{2}, …

⇒_{Case Select}⇒_{Bind}⇒_{Case Select}⇒_{Bind} case true of true : true →^{?} X_{1} ⇒_{Case Select} true →^{?} X_{1} ⇒_{Bind} {}

Thus, the computed solution is {F ↦ λx, y.y}.

6 Correctness and Completeness

As in the first-order case, we show completeness w.r.t. needed reductions. We first define needed reductions and then lift needed reductions to narrowing. In the following we assume an inductively sequential HRS R and assume LNT is invoked with the corresponding definitional trees.

For our purpose it is convenient to define needed reductions via LNT. Then we show that they are in fact needed. For modeling rewriting, the Guess rules are not needed: For LNT we have S ⇒^{∗} _{LNT}^{{}} S′ if and only if no Guess rules are used in the reduction. Hence no narrowing is performed. This can also be seen as an implementation of a particular rewriting strategy.

In order to relate a system of LNT goals to a term, we associate a position p with each case construct and a substitution θ for all newly introduced variables on the right. For each case expression T = case X of … in a rule T′ = f(\overline{X_{n}}) → X we attach the position p of X in the left-hand side of the corresponding rewrite rule. Formally, we define a function l_{T} such that l_{T} (f(\overline{X_{n}}) : X) yields the labeled tree for a rule T = f(\overline{X_{n}}) → X:

– l_{T} (p_{f} : case X of \overline{T_{n}}) = p_{f} : case_{p} X of \overline{l_{T} (T_{n})} where p is the position of X in pat_{T} (p_{f} : case X of \overline{T_{n}})

– l_{T} (p_{f} : r) = p_{f} : r We assume in the following that definitional trees for some inductively sequential HRS R are labeled.

The following invariant will allow us to relate a goal system with a term:

Theorem 4. For an initial goal with case_{ϵ} t of true : true →^{?} X_{1} ⇒^{∗} _{LNT}^{{}} S, S is of one of the following two forms:

1. λ\overline{x}.case_{p_{n}} s of … →^{?} X_{n}, λ\overline{x}.case_{p_{n−1}} λ\overline{y}.X_{n}(\overline{x}, \overline{y}) of … →^{?} X_{n−1}, …, λ\overline{x}.case_{p_{2}} λ\overline{y}.X_{3}(\overline{x}, \overline{y}) of … →^{?} X_{2}, case_{p_{1}} X_{2} of true : true →^{?} X_{1}

2. r →^{?} X_{n+1}, λ\overline{x}.case_{p_{n}} λ\overline{y}.X_{n+1}(\overline{x}, \overline{y}) of … →^{?} X_{n}, λ\overline{x}.case_{p_{n−1}} λ\overline{y}.X_{n}(\overline{x}, \overline{y}) of … →^{?} X_{n−1}, …, λ\overline{x}.case_{p_{2}} λ\overline{y}.X_{3}(\overline{x}, \overline{y}) of … →^{?} X_{2}, case_{p_{1}} X_{2} of true : true →^{?} X_{1}

Furthermore, all \overline{X_{n+1}} are distinct and each variable X_{i} occurs only as shown above, i.e. at most twice in …, e →^{?} X_{i}, case X_{i} of . . ..

Notice that the second form in the above theorem is created by a Case Select rule application, which may reduce a case term to a non-case term, or by Case Eval with a rule f(\overline{X_{n}}) → r. As only the Bind rule applies on such systems, they are immediately reduced to the first form. As we will see, the Bind rule corresponds to the replacement which is part of a rewrite step. Since we now know the precise form of goal systems which may occur, bound variables as arguments and binders are often omitted in goal systems for brevity.

The next goal is to relate LNT and rewriting. For a goal system S, we write S↓ for the normal form obtained by applying Case Eval and Case Select.

Definition 5. We define an associated substitution for each goal system inductively on ⇒^{∗}_{LNT}:

– For an initial goal system of the form S = case_{ϵ} t of true : true →^{?} X, we define the associated substitution θ_{S} = {X ↦ t}.

– For the Case Eval rule on S = λ\overline{x}.case_{p} λ\overline{y}.f(\overline{t}) of … →^{?} X, G with

S ⇒ λ\overline{x}, \overline{y}.σ(X) →^{?} X′, λ\overline{x}.case_{p} λ\overline{y}.X′(\overline{x}, \overline{y}) of … →^{?} X, G =: S′

we define θ_{S′} = θ_{S} ∪ \{X′ ↦ λ\overline{x}.(θ_{S}X)|_{p}\}.

For all other rules, the associated substitution is unchanged.

For a goal system S we write the associated substitution as θ_{S}. Notice that the associated substitution is not a “solution” as used in the completeness result and only serves to reconstruct the original term.

We can translate a goal system produced by LNT into one term as follows. The idea is that case_{p} t of … →^{?} X should be interpreted as the replacement of the case term t at position p in θ_{S}X, i.e., (θ_{S}X)[t]_{p}. Extending this to goal systems yields the following definition:

Definition 6. For a goal system S of the form

[r →^{?} X,] λ\overline{x}.case_{p_{n}} s of … →^{?} X_{n}, …, case_{p_{1}} X_{2} of true : true →^{?} X_{1}

(where [r →^{?} X,] is optional) with associated substitution θ we define the associated term T (S) as (θX_{1})[(θX_{2})[… (θX_{n}(\overline{x}))[θs]_{p_{n}} …]_{p_{2}}]_{p_{1}}.

For instance, if we start with a goal system S_{1} = case_{ϵ} t of true : true →^{?} X, then T (S_{1}) = t.

For a goal system S, we write Bind(S) to denote the result of applying the Case Bind rule. Notice that the substitution of the Bind rule only affects the two leftmost goals.

Lemma 7. Let S = I(t). If S↓ is of the form of Invariant 2, then t = T (S↓) is reducible at position p = p_{1} ⋯ p_{n}. Furthermore, if t ⟶_{p} t′, then I(t′)↓ = Bind(S↓)↓.

Now, we can define needed reductions:

Definition 8. A term t has a needed redex p if I(t)↓ is of Invariant 2 with p = p_{1} ⋯ p_{n}.

It remains to show that needed reductions are indeed needed to compute a constructor headed term.

Theorem 9. If t reduces to true, then t has a needed redex at position p and t must be reduced at p eventually. Otherwise, t is not reducible to true.

The next desirable result is to show that needed reductions are normalizing. This is suggested from related works [15, 11], but is beyond the scope of this paper.

For a goal system S, we call the variables that do not occur in T (S) dummies. In particular, all variables on the right and all variables in selectors in patterns of some tree in S are dummies.

Lemma 10. If S ⇒^{∗} _{LNT}^{θ} {}, then θS ⇒^{∗} _{LNT}^{{}} {}.

Theorem 11 (Correctness of LNT). If I(t) ⇒^{∗} _{LNT}^{θ} {} for a term t, then θt ⟶^{∗} true.

We first state completeness in terms of LNT reductions.

Lemma 12. If θS ⇒^{∗} _{LNT}^{{}} {} and θ is in R-normal form and contains no dummies

of S,^{6} then S ⇒^{∗} _{LNT}^{θ′} {} with θ′ ≤ θ.

Theorem 13 (Completeness of LNT). If θt ⟶^{∗} true and θ is in R-normal form, then I(t) ⇒^{∗} _{LNT}^{θ′} {} with θ′ ≤ θ.

7 Optimality regarding Solutions

We show here another important aspect, namely uniqueness of the solutions computed. Compared to the more general case in [19], optimality of solutions is possible here, since we only evaluate to constructor-headed terms. For this to hold for all subgoals in a narrowing process, our requirement of constructor-based rules is also essential. For these reasons, we never have to chose between Case Select and Case Eval in our setting and optimality follows easily from the corresponding result of higher-order unification.

6 I.e., FV(θ) ∩ FV(S) = FV(T (S))

Theorem 14 (Optimality). If I(t) ⇒^{∗} _{LNT}^{θ} {} and I(t) ⇒^{∗} _{LNT}^{θ′} {} are two different derivations, then θ and θ′ are incomparable.

It is also conjectured that our notion of needed reductions is optimal (this is subject to current research [16, 15, 3]). Note, however, that sharing is needed for optimality, as shown for the first-order case in [2].

8 Avoiding Function Synthesis

Although the synthesis of functional objects by full higher-order unification in LNT is very powerful, it can also be expensive and operationally complex. There is an interesting restriction on rewrite rules which entails that full higher-order unification is not needed in LNT for (quasi) first-order goals.

We show that the corresponding result in [4] is easy to see in our context, although lifting over binders obscures the results somewhat unnecessarily. Lifting may instantiate a first-order variable by a higher-order one, but this is only needed to handle the context correctly.

A term t is quasi first-order if t is a higher-order pattern without free higherorder variables. A rule f(\overline{X_{n}}) → X is called weakly higher-order, if every higherorder free variable which occurs in X is in \{\overline{X_{n}}\}. In other words, higher-order variables may only occur directly below the root and are immediately eliminated when hdts are introduced in the Case Eval rule.

Theorem 15. If I(t) ⇒^{∗}_{LNT} S where t is quasi first-order w.r.t. weakly higherorder rules, then T (S) is quasi first-order.

As a trivial consequence of the last result, Function Guess and Projection do not apply and Imitation is only used as in the first-order case.

9 Conclusions

We have presented an effective model for the integration of functional and logic programming with completeness and optimality results. Since we do not require terminating rewrite rules and permit higher-order logical variables and λ-abstractions, our strategy is a suitable basis for truly higher-order functional logic languages. Moreover, our strategy reduces to an optimal first-order strategy if the higher-order features are not used. Further work will focus on adapting the explicit model for sharing using goal systems from [19] to this refined context.

References

1. S. Antoy. Definitional trees. In Proc. of the 3rd International Conference on Algebraic and Logic Programming, pages 143–157. Springer LNCS 632, 1992.

2. S. Antoy, R. Echahed, and M. Hanus. A needed narrowing strategy. In Proc. 21st ACM Symposium on Principles of Programming Languages, pages 268–279, Portland, 1994.

3. Andrea Asperti and Cosimo Laneve. Interaction systems I: The theory of optimal reductions. Mathematical Structures in Computer Science, 4:457–504, 1994.

4. J. Avenhaus and C. A. Loría-Sáenz. Higher-order conditional rewriting and narrowing. In Jean-Pierre Jouannaud, editor, 1st International Conference on Constraints in Computational Logics, München, Germany, September 1994. Springer LNCS 845.

5. Hendrik Pieter Barendregt. The Lambda Calculus, its Syntax and Semantics. North Holland, 2nd edition, 1984.

6. E. Giovannetti, G. Levi, C. Moiso, and C. Palamidessi. Kernel LEAF: A logic plus functional language. Journal of Computer and System Sciences, 42(2):139–185, 1991.

7. M. Hanus. The integration of functions into logic programming: From theory to practice. Journal of Logic Programming, 19&20:583–628, 1994.

8. M. Hanus. Efficient translation of lazy functional logic programs into Prolog. In Proc. Fifth International Workshop on Logic Program Synthesis and Transformation, pages 252–266. Springer LNCS 1048, 1995.

9. M. Hanus and C. Prehofer. Higher-order narrowing with definitional trees. Technical report 96-2, RWTH Aachen, 1996.

10. J.R. Hindley and J. P. Seldin. Introduction to Combinators and λ-Calculus. Cambridge University Press, 1986.

11. Jan Willem Klop. Combinatory Reduction Systems. Mathematical Centre Tracts 127. Mathematisch Centrum, Amsterdam, 1980.

12. Dale Miller. A logic programming language with lambda-abstraction, function variables, and simple unification. J. Logic and Computation, 1:497–536, 1991.

13. J.J. Moreno-Navarro and M. Rodríguez-Artalejo. Logic programming with functions and predicates: The language BABEL. Journal of Logic Programming, 12:191–223, 1992.

14. Tobias Nipkow. Higher-order critical pairs. In Proc. 6th IEEE Symp. Logic in Computer Science, pages 342–349, 1991.

15. Vincent van Oostrom. Confluence for Abstract and Higher-Order Rewriting. PhD thesis, Vrije Universiteit, 1994. Amsterdam.

16. Vincent van Oostrom. Higher-order families, 1996. In this volume.

17. Christian Prehofer. Higher-order narrowing. In Proc. Ninth Annual IEEE Symposium on Logic in Computer Science, pages 507–516. IEEE Computer Society Press, 1994.

18. Christian Prehofer. A Call-by-Need Strategy for Higher-Order Functional-Logic Programming. In J. Lloyd, editor, Logic Programming. Proc. of the 1995 International Symposium, pages 147–161. MIT Press, 1995.

19. Christian Prehofer. Solving Higher-order Equations: From Logic to Programming. PhD thesis, TU München, 1995. Also appeared as Technical Report I9508.

20. J.R. Slagle. Automated theorem-proving for theories with simplifiers, commutativity, and associativity. Journal of the ACM, 21(4):622–642, 1974.