<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>A Partial Evaluator for Curry</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Michael Hanus</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Björn Peemöller</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Institut für Informatik, CAU Kiel</institution>
          ,
          <addr-line>D-24098 Kiel</addr-line>
          ,
          <country country="DE">Germany</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>We present a partial evaluator for functional logic programs written in Curry. In contrast to previous approaches to the partial evaluation of functional logic programs, we take into account the features used in contemporary Curry programs, in particular, non-deterministic operations and recursive let expressions. For this purpose, we base our partial evaluator on FlatCurry, an intermediate language for the representation of Curry programs. We sketch our approach and present initial benchmarks of our implementation.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Introduction</title>
      <p>Partial evaluation of programs is a technique to anticipate the evaluation of
computations once at compile time instead of performing them (possibly several times) at run
time. This is possible if some part of the input data, also called static data, is known at
compile time. In this case, some parts of the program are evaluated so that a residual
program, i.e., a specialized version of the original one, is returned. Since some
computations have been performed at compile time, the run time of the specialized program
could be considerably decreased. The static data does not need to be some user input,
but can also be subexpressions in the original program. Offline partial evaluators
obtain information about static data from a separate static analysis phase (binding-time
analysis), whereas online partial evaluators obtain this information on the fly and
propagate it during the partial evaluation process. In this work we follow the online partial
evaluation approach.</p>
      <p>
        Partial evaluation has already been studied for different kinds of programming
languages, like functional languages, logic languages, as well as for combined functional
logic languages. An interesting aspect of the partial evaluation of functional logic
programs is the fact that the effects of supercompilation [
        <xref ref-type="bibr" rid="ref23">23</xref>
        ] can be obtained by applying
the operational semantics of the source language (narrowing) at partial evaluation time
[
        <xref ref-type="bibr" rid="ref5">5</xref>
        ]: if a function is called with unknown arguments, narrowing instantiates these
arguments such that the rules defining this function can be applied. Hence, one mainly
needs to control the partial evaluator, i.e., avoiding infinite unfoldings and instantiations
of logic variables, in order to obtain residual programs.
      </p>
      <p>
        Thanks to this insight, partial evaluators for functional logic languages can be
constructed with techniques similarly to the implementation of these languages. For
instance, Albert et al. [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ] proposed a partial evaluator for Curry [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ] based on the
intermediate language FlatCurry. Since FlatCurry makes the evaluation strategy of Curry
programs explicit [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], the use of FlatCurry led to a partial evaluator able to optimize
practical Curry programs. Unfortunately, when this partial evaluator was constructed,
the use of non-deterministic operations, although proposed some years ago [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ], was
not well established. Therefore, the partial evaluation scheme was based on term
rewriting and restricted to confluent programs, i.e., all operations were required to be
deterministic, and recursive let expressions were also not taken into account. Thus, if this
partial evaluator is applied to programs containing non-deterministic operations, which
is a useful programming pattern in contemporary functional logic programs [
        <xref ref-type="bibr" rid="ref6 ref8">6,8</xref>
        ], the
resulting programs are not semantically equivalent to the source programs.
      </p>
      <p>
        In order to deal with realistic Curry programs, it is crucial for a partial evaluator to
cover the full source language, including both logic features such as non-determinism
and functional features such as recursive let expressions. Therefore, we extend in this
work the partial evaluator of Albert et al. [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ] to cover the full language of FlatCurry. In
contrast to [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], we base our partial evaluator on an operational semantics [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] which is
adequate for contemporary Curry programs.
      </p>
      <p>We start with an introduction to the functional logic language Curry in Sect. 2 before
we sketch the structure of the partial evaluator in Sect. 3. The partial evaluation scheme
is presented in Sect. 4, whereas control issues are discussed in Sect. 5. We evaluate our
implementation with some benchmarks in Sect. 6 before we conclude in Sect. 7.
2</p>
    </sec>
    <sec id="sec-2">
      <title>Curry</title>
      <p>
        We briefly review the basic concepts of the functional logic language Curry. More
details can be found in recent surveys on functional logic programming [
        <xref ref-type="bibr" rid="ref15 ref7">7,15</xref>
        ] and in the
language report [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ].
      </p>
      <p>
        The syntax of Curry [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ] is close to Haskell [
        <xref ref-type="bibr" rid="ref21">21</xref>
        ], i.e., type variables and names
of defined operations usually start with lowercase letters and the names of type and
data constructors start with an uppercase letter. The application of an operation f to an
expression e is denoted by juxtaposition (“f e”). In addition to Haskell, Curry allows
free (logic) variables in rules and initial expressions. If the data type of Booleans and a
negation operation are defined by
data Bool = False | True
not True = False
not False = True
the expression “not x where x free” non-deterministically reduces to False with
the binding x = True, and to True with the binding x = False. A further kind of
nondeterminism is supported in Curry by the choice operator “?”, which can be considered
as predefined by the overlapping rules
x ? _ = x
_ ? y = y
coin = 0 ? 1
Thus, we can define a non-deterministic operation coin yielding the values 0 and 1 by
      </p>
      <p>If non-deterministic operations are used as arguments in other operations, a
semantical ambiguity might occur. Consider the operation</p>
      <p>double x = x + x
and the expression “double coin”. If we evaluated this expression by term rewriting,
we could have the reduction
double coin</p>
      <p>
        coin + coin
→ → → →
leading to the unintended result 1. Note that this result cannot be obtained with a strict
reduction strategy where arguments are evaluated prior to the function calls. In order
to avoid dependencies on the evaluation strategies and exclude such unintended results,
Curry is based on the rewriting logic CRWL, proposed by González-Moreno et al. [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ]
as a logical (execution- and strategy-independent) foundation for declarative
programming with non-strict and non-deterministic operations. This logic specifies the call-time
choice semantics [
        <xref ref-type="bibr" rid="ref18">18</xref>
        ] where values of the arguments of an operation are determined
before the operation is evaluated. In a lazy strategy, this can be enforced by sharing actual
arguments. For instance, the expression above can be lazily evaluated provided that all
occurrences of coin are shared so that all of them consistently reduce to either 0 or 1.
0 + coin
      </p>
    </sec>
    <sec id="sec-3">
      <title>Overview of the Partial Evaluator</title>
      <p>
        Before describing the details of the partial evaluation process, we provide an overview
of the partial evaluator and its usage. Since our partial evaluator is an extension of the
first partial evaluator for Curry described in [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], our representation is oriented towards
the original description.
      </p>
      <p>Our partial evaluator is intended to specialize some parts of a given input program
in order to create an optimized, residual program. In order to support the specification
of expressions to be optimized, we assume that these expressions are annotated with
PEVAL. For example, we assume a program which contains the function definition
main xs = map (twice square) xs
We can then annotate the main expression (or parts of it) as follows:</p>
      <p>main xs = PEVAL (map (twice square) xs)
Actually, PEVAL is the identity function, i.e., it has the type a → a. As a consequence,
annotations with PEVAL do not change the semantics of the original program. After
annotating the program, the process of partial evaluation is fully automatic. The process
itself consists of the following phases (depicted in Fig. 1):
1. The partial evaluator is called for a given program, containing annotated
expressions as described above. This source program is converted into the standard
intermediate representation for Curry programs, called FlatCurry (see Sect. 4.1).
2. The process continues by extracting the set of annotated expressions and creating a
copy of the original program without annotations.
3. Both form the input for the partial evaluation phase, which is later described.
4. The output of the partial evaluation is a set of semantically equivalent, potentially
more efficient expressions. These expressions are converted to new function
definitions to allow reuse, a process called renaming.
5. The evaluation process tends to produce some “intermediate” functions which only
pass their parameters to another function. Therefore, the process is finished by a
compression phase which removes such intermediate functions by inlining and
simplifies expressions to produce a more efficient and legible result.
6. Finally, the annotated expressions of the form (PEVAL e) are replaced with their
(hopefully more efficient) equivalents e′, where e′ is the renaming of e. This
optimized program is then stored as a FlatCurry program.</p>
      <p>Annotated
Curry program</p>
      <p>Final
FlatCurry program
(1)
(6)</p>
      <p>Annotated
FlatCurry program</p>
      <p>(2)
Compressed
definitions</p>
      <p>Annotated
expressions
Program without
annotations
(5)
(3)
Residual
expressions</p>
      <p>(4)
New function
definitions
For instance, with the usual definitions of map, twice, and square, the example above
is transformed into
main xs = map0 xs
map0 xs = case xs of []
y:ys
→ []
→ let z = (y*y) in (z*z) : map0 ys
so that the overhead of the higher-order operations map and twice is eliminated.</p>
      <p>
        The fact that the partial evaluator internally operates on the FlatCurry format is no
restriction, since this format is used by current Curry compilers anyway, e.g., PAKCS
[
        <xref ref-type="bibr" rid="ref16">16</xref>
        ] or KiCS2 [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ]. Hence, the partial evaluator can easily be incorporated into a
compilation chain.
4
      </p>
    </sec>
    <sec id="sec-4">
      <title>The Partial Evaluation Scheme</title>
      <p>
        As already mentioned, the partial evaluator described in [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ] lacks support for two
language features, namely non-deterministic operations and let expressions. For instance,
consider the definition
      </p>
      <p>
        main = PEVAL (double coin)
w.r.t. the definitions of coin and double shown in Sect. 2. The partial evaluator [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ]
unfolds the call to double in the body of main to (0 ? 1) + (0 ? 1), so that the
residual program yields the values 0, 1, 1, and 2 for main. However, according to the
call-time choice semantics of Curry [
        <xref ref-type="bibr" rid="ref14 ref18">14,18</xref>
        ], the correct result would be 0 or 2 but not
1. This problem arises from the residual semantics of the original partial evaluator,
which is based on term-rewriting so that non-determinism in shared subexpressions is
duplicated in the residual programs.
      </p>
      <p>
        The second missing feature are (mutually recursive) let expressions, i.e., bindings
where the variables to be bound might occur in the right-hand side of the bindings. For
example, it is not possible to partially evaluate the program
ones = let ones = 1 : ones in ones
main = PEVAL (take 2 ones)
One might encounter that this does not impose a real restriction because recursive
letbindings could be interpreted by recursive function definitions (at the cost of some
overhead). While this is possible for the example above, it is not whenever a
nondeterministic value should be shared. For instance, consider the following program:
digits = let digits = (0 ? 1) : digits in digits
main = PEVAL (take 2 digits)
Because of the let binding, the decision to bind digit to either 0 or 1 is shared, and, in
consequence, the expression main evaluates to either [0,0] or [
        <xref ref-type="bibr" rid="ref1 ref1">1,1</xref>
        ]. If we replaced
the definition of digits by a top-level operation, as in
digits = (0 ? 1) : digits
main = PEVAL (take 2 digits)
the expression main would produce the additional results [
        <xref ref-type="bibr" rid="ref1">0,1</xref>
        ] and [
        <xref ref-type="bibr" rid="ref1">1,0</xref>
        ]. Thus,
recursive let expressions cannot be transformed into operations but must be explicitly
considered by a partial evaluator.
      </p>
      <p>
        The usage of both features in contemporary Curry programs is the motivation for us
to develop a new partial evaluator. In contrast to [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], we do not use a semantics based
on term rewriting. Instead, we base our work on the natural semantics for FlatCurry
proposed in [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] which is intended to specify the call-time choice semantics of
nondeterministic operations by modeling a heap structure to express sharing. A similar
semantics has been used in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] in a partial evaluator for first-order functional programs.
In contrast to our approach, non-determinism, which is essential for Curry, has not been
considered there.
4.1
      </p>
      <sec id="sec-4-1">
        <title>FlatCurry</title>
        <p>
          FlatCurry is a simple intermediate language used by Curry compilers [
          <xref ref-type="bibr" rid="ref11 ref16">11,16</xref>
          ].
Moreover, it is also the basis of precise descriptions of the semantics of Curry [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ] and
semantics-based tools for Curry (e.g., [
          <xref ref-type="bibr" rid="ref2 ref3 ref4">2,3,4</xref>
          ]). The syntax of this representation is
depicted in Fig. 2, where we denote a sequence of objects o1; : : : ; on by on. A FlatCurry
program P consists of a sequence of function definitions D such that each function
must be defined by a single rule with a linear left-hand side, i.e., the variables xn must
be pairwise different. The right-hand side of a function definition is an expression e
composed of variables (x, y, z, . . . ), constructors (A, B, C, . . . ), and function calls (f ,
g, h, . . . ). In the following, we denote by a constructor c or a function f . For the
sake of simplicity, we assume that literals occurring in the source program, like
numbers or characters, are represented as nullary constructors. Additionally, we allow local
(mutually recursive) bindings of variables, the introduction of free (logic) variables,
disjunctions (to represent overlapping left-hand sides in the source language), and
pattern matching. The patterns pi in case expressions are required to be pairwise different
and only consist of constructors applied to variables. In consequence, nested patterns in
the source language are represented by nested case expressions. For example, the list
concatenation conc is represented in FlatCurry as
conc(xs,ys) = case xs of { [] → ys
        </p>
        <p>; z:zs → z : conc(zs,ys) }</p>
        <p>
          Note that, in contrast to [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ], we do not distinguish between flexible and rigid case
expressions. Although they behave differently on free (logic) variables [
          <xref ref-type="bibr" rid="ref17">17</xref>
          ], this
difference is not relevant for partial evaluation [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ]. Furthermore, we omit the representation
of external functions like arithmetics, which are implemented in the partial evaluator
but do not play a significant role in the evaluation scheme. Finally, we do not consider
higher-order applications in the syntax of FlatCurry since they can be represented by an
operation apply where partial applications are interpreted as constructor calls [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ].
4.2
        </p>
      </sec>
      <sec id="sec-4-2">
        <title>Natural Semantics</title>
        <p>
          We base our partial evaluator on a variant of the operational semantics of FlatCurry
[
          <xref ref-type="bibr" rid="ref1">1</xref>
          ], also referred to as the natural semantics of FlatCurry. The semantics uses a heap
structure to specify sharing of expressions and computes the (flat) value of an expression
which is either a logic variable (w.r.t. the associated heap) or a constructor applied to
variables.
        </p>
        <p>Heap = V → {free; ∎} ⊎ Exp</p>
        <p>V alue ∶∶= x S c(xn)
A heap is a partial mapping from a set of variables V to either an expression (Exp is
the set of expressions according to the syntax of FlatCurry), a special symbol “free”
to represent a free variable,1 or a symbol “∎” representing a black hole.2 We denote
the empty heap by [], and the value associated to a variable x in a heap by [x].
[x ↦ e] denotes a heap ′ with ′[x] = e and ′[y] = [y] for all y ≠ x.</p>
        <p>
          We use judgements of the form ∶ e ⇓ ∶ v which express the fact that “the
expression e under the heap evaluates to the value v and the (possibly modified) heap
”. The basic inference rules of the natural semantics are depicted in Fig. 3. We briefly
describe these rules and explain the differences to the original version of [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ].
(Value) Evaluation of a value directly returns the value without modifying the heap.
(VarExp) This rule implements sharing of subexpressions. If a variable to be evaluated
is bound to an expression, the expression is evaluated and its value is returned.
In addition, the heap is updated with the value. During evaluation of the
expression, the binding is replaced by ∎, in contrast to [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ]. This allows the detection of
black holes and is necessary for the correctness of the semantics [
          <xref ref-type="bibr" rid="ref10">10</xref>
          ] (see also
Appendix A for a detailed explanation).
(Flatten) To correctly implement sharing, arguments of function or constructor calls
must be represented in the heap. This is usually achieved by a preprocessing step
called flattening or normalization [
          <xref ref-type="bibr" rid="ref1 ref19">1,19</xref>
          ], but it can also be performed on demand.
1 [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ] represents free variables by circular let bindings of the form let {x = x} in e, but
this prohibits the correct representation of such bindings occurring in the source code.
2 We use a special symbol for black holes instead of simply removing the binding for a variable
(as in [
          <xref ref-type="bibr" rid="ref19">19</xref>
          ]) in order to distinguish black holes from unbound variables.
(VarExp)
where v = c(xn) or v ∈ V with
∶ v
∶ (x1; : : : ; xi−1; ei; ei+1; : : : ; ek) ⇓
∶ v
        </p>
        <p>where ei ∉ V ; y fresh
where f (xn) = e ∈ P;</p>
        <p>= {xn ↦ yn}
∶ (e) ⇓
∶ f (yn) ⇓
∶ v
∶ v
[yk ↦ (ek)] ∶ (e) ⇓
∶ let { xk = ek } in e ⇓
∶ v</p>
        <p>∶ v
∶ ei ⇓
∶ e1 ? e2 ⇓
∶ v</p>
        <p>∶ v
[yn ↦ free] ∶ (e) ⇓
∶ let xn free in e ⇓
∶ v</p>
        <p>∶ v
where i ∈ {1; 2}
where</p>
        <p>= {xk ↦ yk}; yk fresh
where</p>
        <p>= {xn ↦ yn}; yn fresh
∶ e ⇓ ∶ c(yn) ∶ (ei) ⇓
∶ case e of { pk → ek } ⇓
∶ v
∶ v
where pi = c(xn);
= {xn ↦ yn}
∶ e ⇓
[x ↦ free] ∶ x [x ↦ (pi); yn ↦ free] ∶ (ei) ⇓</p>
        <p>
          ∶ case e of { pk → ek } ⇓ ∶ v
where i ∈ {1; : : : ; k}; pi = c(xn); = {xn ↦ yn}; yn fresh
∶ v
Following the general idea of partial evaluation of functional logic programs [
          <xref ref-type="bibr" rid="ref5">5</xref>
          ] as
well as logic programs [
          <xref ref-type="bibr" rid="ref20">20</xref>
          ], we evaluate an annotated expression e with a (possibly
incomplete) standard derivation [] ∶ e ⇓ ∶ e′. In order to ensure the termination of the
partial evaluation process, we defer the evaluation of some expressions. For example,
consider the program
loop xs = loop xs
main xs = PEVAL (loop xs)
The evaluation of the expression main does not terminate due to the recursive function
call to loop. To achieve termination of the partial evaluation process, we modify the
natural semantics as follows:
1. The evaluation of an expression can be deferred to avoid non-termination.
2. An operation proceed is used to decide whether a function call should be unfolded
or deferred.
        </p>
        <p>
          This residualizing natural semantics is similar to [
          <xref ref-type="bibr" rid="ref3 ref4">3,4</xref>
          ] but more complex due to the
use of a heap for sharing instead of term rewriting. Regarding the first modification, we
extend the representation of values with a new symbol ⟪⋅⟫ which encloses expressions
whose evaluation should be deferred.
        </p>
        <p>V alue ∶∶= : : : S ⟪e⟫
(annotated expression)
This annotation directly corresponds to the PEVAL annotation in source programs.
Second, we extend the inference system with the operation proceed , deciding whether a
function call should be unfolded, and replace the rule Fun with:3
∶ (e) ⇓
∶ f (yn) ⇓
∶ f (yn) ⇓
∶ v
∶ v
∶ ⟪f (yn)⟫
where f (xn) = e ∈ P; = {xn ↦ yn};</p>
        <p>proceed ( ; f (yn)) = true
where f (xn) = e ∈ P; = {xn ↦ yn};
proceed ( ; f (yn)) = false
Approaches for the concrete definition of proceed will be discussed in Sect. 5.1.
Furthermore, we extend the rule Value to also return deferred expressions unchanged and
constrain the rule VarExp in that the value must not be a deferred expression. Finally,
we add two more rules for deferred expressions where the annotation is lifted upwards:
In contrast to the evaluation performed in a standard interpreter, the partial
evaluation process has to deal with partial knowledge in the form of unbound variables. For
instance, if the right-hand side of a function declaration like f x = PEVAL (g x)
should be evaluated, there is no binding information for the parameter variable x.
3 Actually, the operation proceed also takes into account the context of reductions already
performed, but we omit them here for the sake of simplicity.</p>
        <p>
          A possible solution is to handle such unbound variables as logic variables, as done
in [
          <xref ref-type="bibr" rid="ref5">5</xref>
          ], so that they are bound to appropriate values by the partial evaluator. Since it
has been shown in [
          <xref ref-type="bibr" rid="ref2">2</xref>
          ] that the back-propagation of these bindings can lead to incorrect
residual programs, [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ] uses a residualizing semantics which represents such bindings
by case expressions in the residual program. However, this is only necessary for
unbound variables. Explicitly introduced logic variables are known to be free during the
actual evaluation so that they can be bound during partial evaluation time. For instance,
consider the expression
        </p>
        <p>
          let x free in case x of { True → 1 }
Here we can bind x to True, since this binding is not visible outside the scope of this
expression, select the (single) branch as the value of the case expression, and continue
by evaluating its right-hand side. In consequence, our implementation evaluates this
expression to 1, while the partial evaluator described in [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ] cannot evaluate the expression
any further.
        </p>
        <p>
          Hence, we distinguish unbound variables from logic variables by not binding them
in the heap. Furthermore, we assume that rule Value is also applicable to variables not
bound in the heap so that unknown variables reduce to themselves. Thus, only the rules
for case expressions have to be changed, where it is now also possible that the
scrutinized value is an unknown variable. Following the idea of [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ], we generate residual
case expressions to defer the inspection of the variable to the run time of the specialized
program. Therefore, we extend the definition of values to
        </p>
        <p>V alue ∶∶= : : : S case x of { pk → vk }
(residual case expression)
where the variable x inspected in the case expression is not bound in the corresponding
heap. Because case expressions are now contained in the set of values, we also have
to consider them as the value of a variable or an expression examined by another case
expression. Hence, we add the following rules:
The general idea is to lift case expressions inspecting an unbound variable upwards
and to defer the evaluation of the alternatives. Such deferred expressions are not further
evaluated in the residual semantics but later extracted by the global iterative process
where
[x] = case y of { p′j → e′j }
∶ e ⇓
∶ x</p>
        <p>case x of
∶ case y of { p′j → ⟪ { pk → ek } ⟫ }
as the initial expressions of a new specialization run. Because the alternatives are then
evaluated independently, it will be possible to take the binding information of the case
expression into account. For instance, if we consider the expression</p>
        <p>case x of { True → not x }
a subsequent evaluation of the right-hand side not x may respect the binding of x to
True and, thus, directly evaluate to False.
After evaluating an expression to a residual value, this value might contain variables
which are either free or bound to expressions in the corresponding heap. To be able
to replace parts of the input program with residual values, these bindings have to be
added to the values to form valid expressions, a process we call dereferencing the heap.
Conceptually, for a given configuration ∶ e, we retrieve the set of variables transitively
reachable from e and bound in and add the corresponding bindings to the expression.
For residual case expressions, we also respect the bindings represented by the case
expression. The bindings are divided into logic variables (fv ) and variables bound to
expressions (bv ) and added to the original expression:
if e = case x of { pk → ek }
otherwise
⎪⎧⎪case x of { pk → drf ( [x ↦ pk]; ek) }
drf ( ; e) = ⎨⎪⎪⟪let fv ( ; e) free in let bv ( ; e) in e⟫</p>
        <p>⎩
For instance, if we consider the configuration
then dereferencing will produce the expression</p>
        <p>[y ↦ free] ∶ case x of {True -&gt; x; False -&gt; y}
case x of { True → ⟪let { x = True } in x⟫;False → ⟪let y free in y⟫ }
5</p>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>Control</title>
      <p>
        Our partial evaluation algorithm follows the general procedure of Alpuente et. al. [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ],
which is parametric w.r.t. an unfolding rule used to construct a finite derivation for an
expression and an abstraction operator used to guarantee that only finitely many
expressions are evaluated. The basic algorithm is depicted in Fig. 4 and works as follows.
Given an input program P and a set of annotated expressions E, the algorithm starts by
applying an unfolding rule which evaluates each expression according to the residual
semantics presented in the previous section and extracts the results by drf . If there is
more than one derivation in the residual semantics due to the non-deterministic
inference rules Or and Guess, the different extracted results of the derivation are combined
by the choice operator “?”. If there is no derivation at all, the result is represented by the
predefined operation failed. In the next step, an abstraction operator is applied to this
set, adding the new expressions to the set of already evaluated expressions. This phase
yields a new set which may need further evaluation, hence, this process is iteratively
repeated until no more expressions are added to the set. This iteration is necessary for the
correctness of partial deduction [
        <xref ref-type="bibr" rid="ref20">20</xref>
        ] in order to achieve a “closed” set of expressions
      </p>
      <sec id="sec-5-1">
        <title>Input: A program P and a set of expressions E Output: A set of expressions S</title>
        <p>i ∶= 0; E0 ∶= E;
repeat</p>
        <p>E′ ∶= unfold (Ei; P );
Ei+1 ∶= abstract (Ei; E′);
i ∶= i + 1;
until Ei = Ei+1 (modulo renaming);
return S ∶= Ei</p>
        <p>
          Fig. 4. Basic algorithm for partial evaluation
that covers all expressions possibly occurring in the residual program. To generate the
resulting program, the same unfolding rule has to be applied to the resulting set of
expressions to generate the corresponding resultants, i.e., the rules of the residual program
(in our implementation, this step is integrated into the algorithm). Finally, the set of
generated resultants are compressed to eliminate intermediate and redundant functions (see
[
          <xref ref-type="bibr" rid="ref5">5</xref>
          ] for details).
        </p>
        <p>This procedure distinguishes two levels of control, namely the local level, managed
by the unfolding rule to avoid infinite evaluations, and the global level, managed by the
abstraction operator to avoid infinitely repetitions of the partial evaluation algorithm. To
ensure termination of the whole process, both local and global termination is required.
5.1</p>
        <sec id="sec-5-1-1">
          <title>Local Control</title>
          <p>
            Termination of the unfolding rule directly corresponds to termination of the residual
semantics presented in Sect. 4. For this purpose, the semantics has already been extended
by an oracle proceed ( ; e) responsible for the decision whether a function call should
be unfolded or not. There exist several well-known techniques in the literature to come
to this decision, e. g., depth-bounds, loop-checks [
            <xref ref-type="bibr" rid="ref9">9</xref>
            ], well-founded orderings [
            <xref ref-type="bibr" rid="ref12">12</xref>
            ], or
well-quasi orderings [
            <xref ref-type="bibr" rid="ref22">22</xref>
            ]. Our implementation currently supports the following simple
strategies:
None No unfolding is performed for user-defined functions.
          </p>
          <p>One Only one function call is unfolded for each evaluation.</p>
          <p>Each At most one call is unfolded for each user-defined function, subsequent calls are
deferred.</p>
          <p>All All function calls are unfolded, which corresponds to the original inference system.</p>
          <p>This does not guarantee termination but may be useful if the user is sure that the
process terminates.</p>
          <p>Note that, regardless of the chosen strategy, built-in functions (such as arithmetics) are
evaluated in any case, since they are known to terminate.</p>
          <p>
            Expressions that have been deferred during evaluation will be extracted and
eventually added to the set of expressions to be evaluated, depending on the operation abstract
(see Sect. 5.2 for details). Generally, a strategy that allows more evaluation steps in
one derivation than another strategy might seem superior. If an evaluation is split into
multiple derivations with deferred subexpressions, each of these subexpressions has to
be evaluated anew and leads to a new residual function to be generated. In contrast,
longer derivations will produce less deferred subexpressions and, hence, less residual
functions. Nevertheless, although a simpler strategy may produce more intermediate
expressions, there are better chances that some of these expressions have already been
encountered before, reducing the overall number of expressions to be evaluated.
Furthermore, the final compression phase will eliminate intermediate functions so that even
the simple strategies perform very well in practice.
The local control is parametric w.r.t. the decision whether to stop or to proceed with the
evaluation, since it is safe to terminate the evaluation at any point. This flexibility does
not apply to the global control because we cannot stop the iterative extension of the set
of expressions until all function calls in this set are “closed” w.r.t. the set of expressions.
An expression e is closed w.r.t. a set of expressions if it is an instance of an expression
in the set and all expressions in the matching substitution are recursively closed (see [
            <xref ref-type="bibr" rid="ref5">5</xref>
            ]
for details). This condition is necessary to ensure the correctness of the partial evaluator
so that the specialized program computes the same solutions as the original program.
In order to avoid the construction of infinite sets of expressions, expressions in this set
are generalized to ensure termination of this process.
          </p>
          <p>Hence, the operation abstract returns a safe approximation of Ei ∪ E′ so that each
expression in the set of Ei ∪ E′ is closed w.r.t. the result of abstract (Ei; E′). More
precisely, an expression e′ ∈ E′ is added to the set Ei according to the following rules
(note that the result of unfolding is either a variable, a deferred expression, a constructor
appplication, a case expression, or a choice of these results):
1. If e′ is a variable, it is discarded.
2. If e′ has the form ⟪e⟫, one of the following options is considered:
(a) add e to the set Ei,
(b) discard the expression e, or
(c) compute the most specific generalization of e and some expression e′ ∈ E′, say
e^, and try to add both e^ and the expressions in the corresponding substitutions
and , where e = (e^) and e′ = (e^).
3. For all other cases (constructor calls, case expressions, choices), the corresponding
subexpressions are considered.</p>
          <p>Like for the unfolding rule, the abstraction can be parameterized by a criterion to decide
the option taken in (2). Our implementation currently supports abstractions using a
wellfounded ordering or an embedding ordering to distinguish between (2a) and (2c), i.e.,
smaller expressions are added but larger expressions are generalized.</p>
          <p>
            To achieve a good level of specialization, it is crucial to recognize different variants
of one expression as equivalent in order to discard them in (2b). This is more
complex in our framework compared to [
            <xref ref-type="bibr" rid="ref3">3</xref>
            ], since we take let expressions into account.
For example, consider the equivalent expressions “map(square,xs)” and “let {f
= square} in map(f,xs)”. If we do not recognize them as variants, they might be
generalized to map(f,xs) which could not further be specialized. Therefore, we
normalize expressions by applying -conversion and flattening [
            <xref ref-type="bibr" rid="ref19">19</xref>
            ] before computing their
abstractions.
allOnes
doubleApp
doubleFlip
lengthApp
kmp
foldr (+) 0 xs (sum)
foldr (+) 0 (map square xs)
foldr (++) [] xs (concat)
map (twice square) xs
foldr (?) failed ys
head (perm ys)
(choose)
          </p>
        </sec>
      </sec>
      <sec id="sec-5-2">
        <title>Time for PE Original Specialized Speedup 280</title>
        <p>In this section we evaluate the implementation of our partial evaluator by some
benchmarks. We compile both the partial evaluator and the benchmarks with the PAKCS
Curry compiler (version 1.11.3, based on SICStus Prolog 4.2.3). All benchmarks were
executed on a Linux machine (Debian Wheezy) with an Intel Core i5-750 (2.66GHz)
processor and 4GiB of memory. The timings were performed using the profiling
operation profileTimeNF of PAKCS and denote the time required for computing the
normal form of the respective result in milliseconds (the arguments passed to the various
functions were evaluated before to bring out the speedup obtained by partial evaluation).
The benchmark examples have been specialized with one unfolding per evaluation and
without any abstraction, since all examples terminated. Experiments with both a
wellfounded ordering or a well-quasi ordering resulted in the same or worse performance.
Table 1 presents the time required for the partial evaluation process itself, for executing
the original and the specialized program, and the gained speedup.</p>
        <p>In the first group of benchmarks, we consider some typical examples of partial
deduction and functional program transformations. These are simple functions working
on lists or trees as (intermediate) data structures: allOnes computes the length of its
input list, represented as Peano numbers, and constructs a new list of the same length
with 1 as all elements, doubleApp is the concatenation of three lists, doubleFlip flips
a tree structure twice, returning the same tree, lengthApp computes the length of the
concatenation of two lists, and kmp implements a generic string pattern matcher. The
first four functions were specialized without static input data, while the kmp example
was specialized w.r.t. a fixed pattern of length 4, explaining both the time needed for
partial evaluation and the gained speedup.</p>
        <p>In the second group, we benchmark some examples with higher-order functions: the
computation of the sum of list elements using foldr, the sum of squared numbers, the
concatenation of a list of lists, and repeatedly applying a function to a list. All functions
are applied to an input list xs containing 200,000 elements. The speedup is generally
achieved because of the removal of intermediate data structures. For instance, the Curry
expression “foldr (+) 0 (map square xs)” is specialized to the following
residual FlatCurry definition:
sumSquare(xs) = case xs of { [] → 0</p>
        <p>; y:ys → (y*y) + sumSquare(ys) }
Finally, we evaluate two (complicated) variants of the function choose, which
nondeterministically chooses one element of a given list ys containing 10,000 elements:
choose (x:xs) = x ? choose xs
Our partial evaluator computes this simple implementation of choose for the first
example. The result for the second example only differs from choose in the order in
which the two non-deterministic alternatives are taken, which stems from the
implementation of perm. The huge speedup is achieved because of the omission of the
nondeterministic intermediate list structure.</p>
        <p>
          To summarize, our partial evaluator shows promising results and is capable of
performing optimizations such as deforestation [
          <xref ref-type="bibr" rid="ref24">24</xref>
          ] and transformation of higher-order
functions to first-order ones. In addition, non-deterministic operations are correctly
specialized in contrast to [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ], and the results for deterministic operations are almost
identical.
7
        </p>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>Conclusions and Future Work</title>
      <p>
        We have presented a new partial evaluation scheme for the functional logic language
Curry based on its intermediate representation FlatCurry. The partial evaluator is based
on an adaptation of the natural semantics of FlatCurry, extending the semantics to deal
with the requirements of partial evaluation such as ensuring termination. In contrast
to the original partial evaluator [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], which is based on term rewriting without
sharing, the new implementation correctly handles both recursive let expressions and
non-deterministic operations and, thus, supports full (Flat)Curry. As our benchmarks
demonstrate, the implementation is capable of powerful optimizations both to
deterministic and non-deterministic programs.
      </p>
      <p>
        For future work, we intend to formally prove the correctness of the partial
evaluation scheme, which should be manageable due to the similarity of the original and
residual semantics. Another aspect for further investigations is the improvement of the
abstraction operator. While the abstraction is necessary to ensure termination, a too
general abstraction reduces the quality of the specialization. Thus, more sophisticated
abstraction operators might be beneficial.
As mentioned in Sect. 4.2, rule VarExp of the natural semantics shown in Fig. 3
replaces the variable binding x ↦ e by x ↦ ∎ in the heap when evaluating the associated
expression e. This allows the detection of black holes (a self-dependent infinite loop)
[
        <xref ref-type="bibr" rid="ref19">19</xref>
        ], as done in some implementations of functional (logic) languages. For instance,
an attempt to evaluate the expression “let {x = x} in x” would result in a finite
but incomplete derivation tree, whereas it would trigger the construction of an infinite
derivation tree if the binding x ↦ e was kept.
      </p>
      <p>
        The detection of black holes included in the semantics seems to be an optimization
that could be omitted for deterministic programs [
        <xref ref-type="bibr" rid="ref19">19</xref>
        ]. However, it is crucial in
combination with non-determinism in order to prevent the binding of a variable to different
values in the same derivation, as shown in [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ]. For example, consider the expression
“let { x = T ? case x of { T → F }} in x”. If we do not replace the
variable binding in rule VarExp, the following derivation would be possible:
∶ T ⇓ ∶ T
∶ T ? case x of { T → F } ⇓
      </p>
      <p>∶ T
∶ x ⇓ [x ↦ T] ∶ T [x ↦ T] ∶ F ⇓ [x ↦ T] ∶ F</p>
      <p>∶ case x of { T → F } ⇓ [x ↦ T] ∶ F
∶ T ? case x of { T → F } ⇓ [x ↦ T] ∶ F</p>
      <p>∶ x ⇓ [x ↦ F] ∶ F
[] ∶ let { x = T ? case x of { T → F } } in x ⇓ [x ↦ F] ∶ F
where</p>
      <p>= [x ↦ T ? case x of { T → F }]
In this derivation, the variable x is looked up in the heap twice, where at first the right
(non-deterministic) branch is chosen and afterwards the left branch. Hence, x is bound
to T as well as F, which violates the single assignment property of call-time choice.</p>
      <p>With our semantics, there is one successful and one failing derivation but no
derivation where x is bound to T as well as F:</p>
      <p>[x ↦ ∎] ∶ T ⇓ [x ↦ ∎] ∶ T
[x ↦ ∎] ∶ T ? case x of { T → F } ⇓ [x ↦ ∎] ∶ T
[x ↦ T ? case x of { T → F }] ∶ x ⇓ [x ↦ T] ∶ T
[] ∶ let { x = T ? case x of { T → F } } in x ⇓ [x ↦ T] ∶ T</p>
      <p>[x ↦ ∎] ∶ x ⇓ failure
[x ↦ ∎] ∶ case x of { T → F } ⇓
[x ↦ ∎] ∶ T ? case x of { T → F } ⇓
[x ↦ T ? case x of { T → F }] ∶ x ⇓
[] ∶ let { x = T ? case x of { T → F } } in x ⇓
B</p>
    </sec>
    <sec id="sec-7">
      <title>Residualizing Semantics</title>
      <p>Since the various rules of the residualizing semantics used in our partial evaluator are
distributed over the paper and some of them were only informally sketched, we
summarize in the following the complete set of rules of our residualizing semantics.
(VarDefer)
(Flatten)
(FunDefer)
(Free)
(Guess)
(CaseUnbound)
(CaseVarCase)</p>
      <p>[x ↦ ∎] ∶ e ⇓ ∶ v
[x ↦ e] ∶ x ⇓ [x ↦ v] ∶ v</p>
      <p>[x ↦ ∎] ∶ e ⇓ ∶ ⟪e′⟫
[x ↦ e] ∶ x ⇓ [x ↦ e′] ∶ ⟪x⟫
where aen∉d{(fvre∈e;V∎o}r v = c(xn))</p>
      <p>where e ∉ {free;∎}
[x ↦ ∎] ∶ e ⇓ ∶ case y of{ pk → ⟪ek⟫ }
[x ↦ e] ∶ x ⇓ [x ↦ case y of{ pk → ek }] ∶ x
[y ↦ ei] ∶ (x1;:::;xi−1;y;ei+1;:::;ek) ⇓ ∶ v</p>
      <p>∶ (x1;:::;xi−1;ei;ei+1;:::;ek) ⇓ ∶ v</p>
      <p>where fpr(oxcnee)d=(e;∈fP(;yn)=){=xtnru↦e yn};
∶ f(yn) ⇓ ∶ ⟪f(yn)⟫ where fpr(oxcnee)d=(e;∈fP(;yn)=){=xfnal↦seyn};
where e ∉ {free;∎}</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <given-names>E.</given-names>
            <surname>Albert</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          ,
          <string-name>
            <given-names>F.</given-names>
            <surname>Huch</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Oliver</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Vidal</surname>
          </string-name>
          .
          <article-title>Operational semantics for declarative multi-paradigm languages</article-title>
          .
          <source>Journal of Symbolic Computation</source>
          ,
          <volume>40</volume>
          (
          <issue>1</issue>
          ):
          <fpage>795</fpage>
          -
          <lpage>829</lpage>
          ,
          <year>2005</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <given-names>E.</given-names>
            <surname>Albert</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Vidal</surname>
          </string-name>
          .
          <article-title>Using an abstract representation to specialize functional logic programs</article-title>
          .
          <source>In Proc. of the 7th International Conference on Logic for Programming and Automated Reasoning (LPAR</source>
          <year>2000</year>
          ), pages
          <fpage>381</fpage>
          -
          <lpage>398</lpage>
          . Springer LNCS
          <year>1955</year>
          ,
          <year>2000</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <given-names>E.</given-names>
            <surname>Albert</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Vidal</surname>
          </string-name>
          .
          <article-title>A practical partial evaluator for a multi-paradigm declarative language</article-title>
          .
          <source>Journal of Functional and Logic Programming</source>
          ,
          <source>2002(1)</source>
          ,
          <year>2002</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <string-name>
            <given-names>E.</given-names>
            <surname>Albert</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Vidal</surname>
          </string-name>
          .
          <article-title>A residualizing semantics for the partial evaluation of functional logic programs</article-title>
          .
          <source>Information Processing Letters</source>
          ,
          <volume>85</volume>
          (
          <issue>1</issue>
          ):
          <fpage>19</fpage>
          -
          <lpage>25</lpage>
          ,
          <year>2003</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <string-name>
            <given-names>M.</given-names>
            <surname>Alpuente</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Falaschi</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Vidal</surname>
          </string-name>
          .
          <article-title>Partial evaluation of functional logic programs</article-title>
          .
          <source>ACM Transactions on Programming Languages and Systems</source>
          ,
          <volume>20</volume>
          (
          <issue>4</issue>
          ):
          <fpage>768</fpage>
          -
          <lpage>844</lpage>
          ,
          <year>1998</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          6.
          <string-name>
            <given-names>S.</given-names>
            <surname>Antoy</surname>
          </string-name>
          .
          <article-title>Optimal non-deterministic functional logic computations</article-title>
          .
          <source>In Proc. International Conference on Algebraic and Logic Programming (ALP'97)</source>
          , pages
          <fpage>16</fpage>
          -
          <lpage>30</lpage>
          . Springer LNCS 1298,
          <year>1997</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7.
          <string-name>
            <given-names>S.</given-names>
            <surname>Antoy</surname>
          </string-name>
          and
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          .
          <article-title>Functional logic programming</article-title>
          .
          <source>Communications of the ACM</source>
          ,
          <volume>53</volume>
          (
          <issue>4</issue>
          ):
          <fpage>74</fpage>
          -
          <lpage>85</lpage>
          ,
          <year>2010</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <string-name>
            <given-names>S.</given-names>
            <surname>Antoy</surname>
          </string-name>
          and
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          .
          <article-title>New functional logic design patterns</article-title>
          .
          <source>In Proc. of the 20th International Workshop on Functional</source>
          and
          <article-title>(Constraint) Logic Programming (WFLP</article-title>
          <year>2011</year>
          ), pages
          <fpage>19</fpage>
          -
          <lpage>34</lpage>
          . Springer LNCS 6816,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          9.
          <string-name>
            <given-names>R.N.</given-names>
            <surname>Bol</surname>
          </string-name>
          .
          <article-title>Loop checking in partial deduction</article-title>
          .
          <source>Journal of Logic Programming</source>
          ,
          <volume>16</volume>
          (
          <issue>1</issue>
          &amp;2):
          <fpage>25</fpage>
          -
          <lpage>46</lpage>
          ,
          <year>1993</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          10.
          <string-name>
            <given-names>B.</given-names>
            <surname>Braßel</surname>
          </string-name>
          .
          <article-title>Implementing Functional Logic Programs by Translation into Purely Functional Programs</article-title>
          .
          <source>PhD thesis</source>
          ,
          <source>Christian-Albrechts-Universität zu Kiel</source>
          ,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          11.
          <string-name>
            <given-names>B.</given-names>
            <surname>Braßel</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          ,
          <string-name>
            <given-names>B.</given-names>
            <surname>Peemöller</surname>
          </string-name>
          , and
          <string-name>
            <given-names>F.</given-names>
            <surname>Reck</surname>
          </string-name>
          .
          <article-title>KiCS2: A new compiler from Curry to Haskell</article-title>
          .
          <source>In Proc. of the 20th International Workshop on Functional</source>
          and
          <article-title>(Constraint) Logic Programming (WFLP</article-title>
          <year>2011</year>
          ), pages
          <fpage>1</fpage>
          -
          <lpage>18</lpage>
          . Springer LNCS 6816,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          12.
          <string-name>
            <surname>M. Bruynooghe</surname>
            , D. De Schreye, and
            <given-names>B.</given-names>
          </string-name>
          <string-name>
            <surname>Martens</surname>
          </string-name>
          .
          <article-title>A general criterion for avoiding infinite unfolding</article-title>
          .
          <source>New Generation Computing</source>
          ,
          <volume>11</volume>
          (
          <issue>1</issue>
          ):
          <fpage>47</fpage>
          -
          <lpage>79</lpage>
          ,
          <year>1992</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          13.
          <string-name>
            <given-names>S.</given-names>
            <surname>Fischer</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Silva</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Tamarit</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Vidal</surname>
          </string-name>
          .
          <article-title>Preserving sharing in the partial evaluation of lazy functional programs</article-title>
          . In A. King, editor,
          <source>Logic-based Program Synthesis and Transformation (revised and selected papers from LOPSTR'07)</source>
          , pages
          <fpage>74</fpage>
          -
          <lpage>89</lpage>
          . Springer LNCS 4915,
          <year>2008</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          14.
          <string-name>
            <surname>J.C. González-Moreno</surname>
            ,
            <given-names>M.T.</given-names>
          </string-name>
          <string-name>
            <surname>Hortalá-González</surname>
            ,
            <given-names>F.J.</given-names>
          </string-name>
          <string-name>
            <surname>López-Fraguas</surname>
            , and
            <given-names>M. RodríguezArtalejo.</given-names>
          </string-name>
          <article-title>An approach to declarative programming based on a rewriting logic</article-title>
          .
          <source>Journal of Logic Programming</source>
          ,
          <volume>40</volume>
          :
          <fpage>47</fpage>
          -
          <lpage>87</lpage>
          ,
          <year>1999</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          15.
          <string-name>
            <given-names>M.</given-names>
            <surname>Hanus</surname>
          </string-name>
          .
          <article-title>Functional logic programming: From theory to Curry</article-title>
          .
          <source>In Programming Logics - Essays in Memory of Harald Ganzinger</source>
          , pages
          <fpage>123</fpage>
          -
          <lpage>168</lpage>
          . Springer LNCS 7797,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          16.
          <string-name>
            <surname>M. Hanus</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          <string-name>
            <surname>Antoy</surname>
            ,
            <given-names>B.</given-names>
          </string-name>
          <string-name>
            <surname>Braßel</surname>
            ,
            <given-names>M.</given-names>
          </string-name>
          <string-name>
            <surname>Engelke</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          <string-name>
            <surname>Höppner</surname>
            ,
            <given-names>J.</given-names>
          </string-name>
          <string-name>
            <surname>Koj</surname>
            ,
            <given-names>P.</given-names>
          </string-name>
          <string-name>
            <surname>Niederau</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          <string-name>
            <surname>Sadre</surname>
            , and
            <given-names>F.</given-names>
          </string-name>
          <string-name>
            <surname>Steiner</surname>
          </string-name>
          . PAKCS:
          <article-title>The Portland Aachen Kiel Curry System</article-title>
          . Available at http: //www.informatik.uni-kiel.de/~pakcs/,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          17. M. Hanus (ed.).
          <source>Curry: An integrated functional logic language (vers. 0.8.3)</source>
          . Available at http://www.curry-language.org,
          <year>2012</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          18.
          <string-name>
            <given-names>H.</given-names>
            <surname>Hussmann</surname>
          </string-name>
          .
          <article-title>Nondeterministic algebraic specifications and nonconfluent term rewriting</article-title>
          .
          <source>Journal of Logic Programming</source>
          ,
          <volume>12</volume>
          :
          <fpage>237</fpage>
          -
          <lpage>255</lpage>
          ,
          <year>1992</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          19.
          <string-name>
            <given-names>J.</given-names>
            <surname>Launchbury</surname>
          </string-name>
          .
          <article-title>A natural semantics for lazy evaluation</article-title>
          .
          <source>In Proc. 20th ACM Symposium on Principles of Programming Languages (POPL'93)</source>
          , pages
          <fpage>144</fpage>
          -
          <lpage>154</lpage>
          . ACM Press,
          <year>1993</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref20">
        <mixed-citation>
          20.
          <string-name>
            <given-names>J.W.</given-names>
            <surname>Lloyd</surname>
          </string-name>
          and
          <string-name>
            <given-names>J.C.</given-names>
            <surname>Shepherdson</surname>
          </string-name>
          .
          <article-title>Partial evaluation in logic programming</article-title>
          .
          <source>Journal of Logic Programming</source>
          ,
          <volume>11</volume>
          :
          <fpage>217</fpage>
          -
          <lpage>242</lpage>
          ,
          <year>1991</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref21">
        <mixed-citation>
          21. S. Peyton Jones, editor.
          <source>Haskell 98 Language and Libraries-The Revised Report</source>
          . Cambridge University Press,
          <year>2003</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref22">
        <mixed-citation>
          22.
          <string-name>
            <surname>M.H. Sørensen</surname>
            and
            <given-names>R.</given-names>
          </string-name>
          <string-name>
            <surname>Glück</surname>
          </string-name>
          .
          <article-title>An algorithm of generalization in positive supercompilation</article-title>
          .
          <source>In Proc. of the 1995 International Logic Programming Symposium</source>
          , pages
          <fpage>465</fpage>
          -
          <lpage>479</lpage>
          . MIT Press,
          <year>1995</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref23">
        <mixed-citation>
          23.
          <string-name>
            <given-names>V.F.</given-names>
            <surname>Turchin</surname>
          </string-name>
          .
          <article-title>The concept of a supercompiler</article-title>
          .
          <source>ACM Transactions on Programming Languages and Systems</source>
          ,
          <volume>8</volume>
          (
          <issue>3</issue>
          ),
          <year>1986</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref24">
        <mixed-citation>
          24.
          <string-name>
            <given-names>P.</given-names>
            <surname>Wadler</surname>
          </string-name>
          . Deforestation:
          <article-title>Transforming programs to eliminate trees</article-title>
          .
          <source>Theoretical Computer Science</source>
          ,
          <volume>73</volume>
          :
          <fpage>231</fpage>
          -
          <lpage>248</lpage>
          ,
          <year>1990</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>