<!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>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Sergio Antoy</string-name>
          <email>antoy@cs.pdx.edu</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Michael Hanus</string-name>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Computer Science Dept., Portland State University</institution>
          ,
          <addr-line>Oregon</addr-line>
          ,
          <country country="US">U.S.A</country>
        </aff>
        <aff id="aff1">
          <label>1</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>Curry is a successful, general-purpose, functional logic programming language that predefines a singleton type Success explicitly to support its logic component. We take the likely-controversial position that without Success Curry would be as much logic or more. We draw a short history and motivation for the existence of this type and justify why its elimination could be advantageous. Furthermore, we propose a new interpretation of rule application which is convenient for programming and increases the similarity between the functional component of Curry and functional programming as in Haskell. We outline some related theoretical (semantics) and practical (implementation) consequences of our proposal.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Motivation</title>
      <p>
        Recently, we coded a small Curry [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ] module to encode and pretty-print JSON
formatted documents [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ]. The JSON format encodes floating point numbers with a syntax
that makes the decimal point optional. Our Curry System prints floating numbers with a
decimal point. Thus, integers, which were converted to floats for encoding, were printed
as floats, e.g., the integer value 2 was printed as “2.0”. We found all those point-zeros
annoying and distracting and decided to get rid of them. To avoid messing with the
internal representation of numbers, and risking losing information, our algorithm would
look for “.0” at the end of the string representation of a number in the JSON document
and remove it. In the List library, we found a function, isSuffixOf, that tells us whether to
drop the last two characters, but we did not find a function to drop the last 2 characters.
How could we do that?
      </p>
      <p>In the library we found the usual drop and take functions that work at the beginning
of a string s. Hence, we could reverse s, drop 2 characters, and reverse again. We were
not thrilled. Or we could take from s the first n 2 characters, where n is the length of
s. We were not thrilled either. In both cases, conceptually the string is traversed 3 times
(probably in practice too) and extraneous functions are invoked. Not a big deal, but
there must be a better way. Although the computation is totally functional, we started
to think logic.</p>
      <p>
        Curry has this fantastic feature called functional patterns [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ]. With it, we could code
the following:
fix int (x ++ ".0") = x
Now we were thrilled! This is compact, simple and obviously correct. Of course, we
would need a rule for cases in which the string representation of a number does not end
in “.0”, i.e.:
fix int (x ++ ".0") = x
fix int x = x (2)
Without the last rule fix int would fail on a string such as “2.1”. With the last rule the
program would be incorrect because both rules would be applied for a number that
ends in “.0”. The latter is a consequence of the design decision that established that the
order of the rules in a program is irrelevant—a major departure of Curry from popular
functional languages. One of the reasons of this design decision is Success.
2
      </p>
    </sec>
    <sec id="sec-2">
      <title>History</title>
      <p>Putting it crudely, a functional logic language is a functional language extended with
logic variables. The only complication of this extension is what to do when some
function f is applied to some unbound logic variable u. There are two options, either to
residuate on u or to narrow u. Residuation suspends the application of f, and computes
elsewhere in the program in hopes that this computation will narrow u so that the
suspended application of f can continue. Narrowing instantiates u to values that sustain
the computation. For example, given the usual concatenation of lists:
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys) (3)
Narrowing u ++ t, where u is unbound and t is any expression, instantiates u to []
and u0:us and continues these computations either one at the time or concurrently
depending on the control strategy.</p>
      <p>
        In early functional logic languages [
        <xref ref-type="bibr" rid="ref1 ref17">1, 17</xref>
        ], in the tradition of logic programming,
only predicates (as opposed to any function) are allowed to instantiate a logic variable.
In the early days of Curry, we were not brave enough. Indiscriminate narrowing, such as
that required for (1), which is based on (3), was uncharted territory and we decided that
all functions would residuate except a small selected group called constraints. These
functions are characterized by returning a singleton type called Success.
      </p>
      <p>
        Narrowing has the remarkable property of solving equations [
        <xref ref-type="bibr" rid="ref23">23</xref>
        ]. Indeed, the rule
in (1) works by solving an equation by narrowing. An application fix int(s), where s is a
string, attempts to solve s = x++".0". A solution, “the” if any exists, gives the desired
result x. Returning Success rather than Boolean, as the constrained equality does, had
the desirable consequence that we would not “solve” an equation by deriving it to False,
but had the drawback of introducing a new variant of equality, implemented in Curry
by the operation “=:=”, and the undesirable consequence that “some expressions were
more equal than others” [
        <xref ref-type="bibr" rid="ref19">19</xref>
        ].
      </p>
      <p>As a consequence of our hesitation, narrowing was limited to the arguments of
constraints—a successful model well-established by Prolog. However, this model is at
odds with a language with a functional component with normal (lazy) order of
evaluation. Without functional nesting, there is no easy way to tell whether or not some
argument of some constraint should be evaluated. Consider a program to solve the
8queens puzzle:
permute x y = : : : succeed if y is a permutation of x
safe y = : : : succeed if y is a safe placement of queens
(4)
A solution of the puzzle is obtained by permute [1::8] y &amp;&amp; safe y, where y is likely a
free variable. The constraint permute fully evaluates y upon returning even if safe may
only look at the first two elements and determine that y is not safe.</p>
      <p>This prompted the invention of “non-deterministic functions”, i.e., a function-like
mechanism, that may return more than one value for the same combination of
arguments, but is used as an ordinary function. With this idea, Example (4) is coded as:
permute x = : : : return any permutation of x
safe y = : : : as before (5)
In this case, a solution of the puzzle is obtained by safe y where y = permute [1::8].
Since y is nested inside safe, permute [1::8] can be evaluated only to the extent needed
by its context. A plausible encoding of permute is:
permute [] = []
permute (x : xs) = nd insert x (permute xs)
nd insert x ys = x : ys
nd insert x (y : ys) = y : nd insert x ys
The evaluation of permute [1::8] produces any permutation of [1::8] only if both rules
defining nd insert are applied when the second argument is a non-empty list. Thus, the
well-established convention of functional languages that the first rule that matches an
expression is the only one being fired had to be changed in the design of Curry.
(6)
(8)
Our modest proposal is to strip the Success type of any special meaning. Since
Success is isomorphic to the Unit type, which is already defined in the Prelude, probably
it becomes redundant. Future versions of the language could keep it for backward
compatibility, but deprecate it.</p>
      <p>The first consequence of this change puts in question the usefulness of “=:=”, the
constrained equality. Equations can be solved using the Boolean equality “==”
bringing Curry more in line with functional languages. To solve an equation by narrowing,
we simply evaluate it using the standard rules defining Boolean equality. For example,
below we show these rules for a polymorphic type List:
[] == [] = True
(x:xs) == (y:ys) = x==y &amp;&amp; xs==ys
[] == (-:-) = False (7)
(-:-) == [] = False
However, we certainly want to avoid binding variables with instantiations that derive
an equation to False since these bindings are not solutions. Avoiding these bindings is
achieved with the following operation:</p>
      <p>solve True = True
3</p>
    </sec>
    <sec id="sec-3">
      <title>Proposed Adjustments</title>
      <p>and wrapping an equation with solve, i.e., to solve x = y, we code solve (x == y).
Nostalgic programmers could redefine “=:=” as:
x =:= y = solve (x == y)
(9)
When an equation occurs in the condition of a rule, the intended behavior is implied,
i.e., the rule is fired only when the condition is (evaluates to) True.</p>
      <p>In a short paragraph above, we find the symbols “=”, “==” and “=:=”. The first
one is the (mathematical) equality. The other two are (computational) approximations
of it with subtle differences. Our proposal simplifies this situation by having only “==”
as the implementation of “=”, as in functional languages, without sacrificing any of
Curry’s logic aspects.</p>
      <p>The second consequence of our proposal is to review the rule selection strategy,
i.e., the order, or more precisely its lack thereof, in which rules are fired. We have
already hinted at this issue discussing example (2). Every rule that matches the
arguments and satisfies the condition of a call is non-deterministically fired. A motivation
for the independence of rule order was discussed in example (6). The ability of making
non-deterministic choices is essential to functional logic programming, and it must be
preserved, but it can be achieved in a different way.</p>
      <p>
        The predefined operation “?” non-deterministically returns either of its arguments.
This operation allows us to express non-determinism in a way different from rules
with overlapping left-hand sides [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ]. For instance, the non-determinism of the
operation nd insert in (6) can be moved from the left-hand sides of its defining rules to the
right-hand sides as in the following definition:
nd insert x ys = (x : ys) ? nd insert2 x ys
nd insert2 x (y : ys) = y : nd insert x ys (10)
Indeed, some Curry compilers, like KiCS2 [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ], implement this transformation.
      </p>
      <p>
        The definition of Curry at the time of this writing [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ] establishes that the order of
the rules defining an operation is irrelevant. The same holds true for the conditions of
a rule, except in the case in which the condition type is Boolean, and for flexible case
expressions. Our next proposal is to change this design decision of Curry. Although
this is somehow independent of our first proposal to remove the Success type, it is
reasonable to consider both proposals at once since both simplify the use of Curry.
      </p>
      <p>We propose to change the current definition of rule application in Curry as follows.
To determine which rule(s) to fire for an application t = f (t1; : : : ; tn), where f is an
operation and t1; : : : ; tn are expressions, use the following strategy:
1. Scan the rules of f in textual order. An unconditional rule is considered as a
conditional rule with condition True.
2. Fire the first rule whose left-hand side matches the application t and whose
condition is satisfied. Ignore any remaining rule.
3. If no rule can be applied, the computation fails.
4. If a combination of arguments is non-deterministic, the previous points are executed
independently for each non-deterministic choice of the combination of arguments.
In particular, if an argument is a free variable, it is non-deterministically instantiated
to all its possible values.</p>
      <p>
        As usual in a non-strict language like Curry, arguments of an operation application
are evaluated as they are demanded by the operation’s pattern matching and condition.
However, any non-determinism or failure during argument evaluation is not passed
inside the condition evaluation. A precise definition of “inside” is in [6, Def. 3]. This is
quite similar to the behavior of set functions to encapsulate internal non-determinism
[
        <xref ref-type="bibr" rid="ref6">6</xref>
        ]. Apropos, we discuss in Section 5 how to exploit set functions to implement this
concept.
      </p>
      <p>Before discussing the advantages and implementation of this concept, we explain
and motivate the various design decisions taken in our proposal. First, it should be noted
that this concept distinguishes non-determinism outside and inside a rule application.
If the condition of a rule has several solutions, this rule is applied if it is the first one
with a true condition. Second, the computation proceeds non-deterministically with all
the solutions of the condition. For instance, consider an operation to look up values for
keys in an association list:
lookup key assoc
| assoc == (- ++ [(key,val)] ++ -)
= Just val (11)
where val free
lookup - - = Nothing
If we evaluate lookup 2 [(2; 14); (3; 17); (2; 18)], the condition of the first rule is
solvable. Thus, we ignore the remaining rules and apply only the first rule to evaluate this
expression. Since the condition has the two solutions fval 7! 14g and fval 7! 18g, we
yield the values Just 14 and Just 18 for this expression. Note that this is in contrast to
Prolog’s if-then-else construct which checks the condition only once and proceeds just
with the first solution of the condition. If we evaluate lookup 2 [(3; 17)], the condition
of the first rule is not solvable but the second rule is applicable so that we obtain the
result Nothing.</p>
      <p>On the other hand, non-deterministic arguments might trigger different rules to be
applied. Consider the expression lookup (2?3) [(3; 17)]. Since the non-determinism in
the arguments leads to independent rule applications (see item 4), this expression leads
to independent evaluations of lookup 2 [(3; 17)] and lookup 3 [(3; 17)]. The first one
yields Nothing, whereas the second one yields Just 17.</p>
      <p>
        Similarly, free variables as arguments might lead to independent results since free
variables are equivalent to non-deterministic values [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ]. For instance, the expression
lookup 2 xs yields the value Just v with the binding fxs 7! (2; v): g, but also the
value Nothing with the binding fxs 7! []g (as well as many other solutions). Again,
this behavior is different from Prolog’s if-then-else construct which performs bindings
for free variables inside the condition independently of its source. In contrast to Prolog,
our design supports completeness in logic-oriented computations even in the presence
of if-then-else.
      </p>
      <p>The latter desirable property has also implications for the handling of failures
occurring when arguments are evaluated. For instance, consider the expression “lookup 2
failed” (where failed is a predefined operation which always fails whenever it is
evaluated). Because the evaluation of the condition of the first rule fails, the entire expression
evaluation fails instead of returning the value Nothing. This is motivated by the fact that
we need the value of the association list in order to check the satisfiability of the
condition, but this value is not available.</p>
      <p>isUnit x | x == () = True
isUnit - = False
(12)</p>
      <p>To see the consequences of an alternative design decision, consider the following
contrived definition of an operation that checks whether its argument is the unit value
() (which is the only value of the unit type):
In our proposal, the evaluation of isUnit failed fails. In an alternative design (like
Prolog’s if-then-else construct), one might skip any failure during condition checking and
proceed with the next rule. In this case, we would return the value False for the
expression isUnit failed. This is quite disturbing since the (deterministic!) operation isUnit,
which has only one possible input value, could return two values: True for the call
isUnit () and False for the call isUnit failed. Moreover, if we call this operation with
a free variable, like isUnit x, we obtain the single binding fx 7! ()g and value True
(since free variables are never bound to failures). Thus, either our semantics would
be incomplete for logic computations or we compute too many values. In order to get
a consistent behavior, we require that failures of arguments demanded for condition
checking lead to failures of evaluations.</p>
      <p>
        Changing the meaning of rule selection from an order-independent semantics to a
sequential interpretation is an important change in the design of Curry. However, this
change is relevant only for a relatively small amount of existing programs. First, most of
the operations in a functional logic program are inductively sequential [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ], i.e., they are
defined by rules where the left-hand sides do not overlap. Hence, the order of the rules
does not affect the definition of such operations. Second, rules defined with traditional
Boolean guards residuate if they are applied to unknown arguments, i.e., it is usually
not intended to apply alternative conditions to a given call. This fits to a sequential
interpretation of conditions. Moreover, our proposal supports the use of conditional
rules in a logic programming manner with unknown arguments, since this “outside”
non-determinism does not influence the sequential condition checking.
      </p>
      <p>Nevertheless, there are also cases where a sequential interpretation of rules is not
intended, e.g., in a rule-oriented programming style, which is often used in
knowledgebased or constraint programming. Although we argued that one can always translate
overlapping patterns into rules with non-overlapping patterns by using the choice
operator “?”, the resulting code might be less readable. Finally, we have to admit that in a
declarative language ignoring the order of the rules is more elegant though not always
as convenient. Hence, a good compromise would be a compiler pragma that allows to
choose between a sequential or an unordered interpretation of overlapping rules.
4</p>
    </sec>
    <sec id="sec-4">
      <title>Advantages</title>
      <p>In this section we justify through exemplary problems the advantages of the proposed
changes.</p>
      <p>Example 1. With the proposed semantics, (2) is a simple and obviously correct
solution of the problem, discussed in the introduction, of “fixing” the representation of
integers in a JSON document.</p>
      <p>Example 2. As in the previous example, our proposed semantics is compatible with
functional patterns. Hence, (11) can be more conveniently coded as:
lookup key (- ++ [(key,val)] ++ -) = Just val
lookup - - = Nothing</p>
      <p>Example 3. Consider a read-eval-print loop of a functional logic language such
as Curry. A top-level expression may contain free variables that are declared by a free
clause such as in the following example:</p>
      <p>
        x ++ y == [
        <xref ref-type="bibr" rid="ref1 ref2 ref3 ref4">1,2,3,4</xref>
        ] where x, y free
Of course, the free clause is absent if there are no free variables in the top-level
expression. The free variables, when present, are easily extracted with a “deep” pattern as
follows:
breakFree (exp++" where "++wf++" free"))
      </p>
      <p>= (exp,wf)
breakFree exp (15)
= (exp,"")
For this code to work, the rules of breakFree must be tried in order and the second
one must be fired only if the first one fails.</p>
      <p>Example 4. Suppose that World Cup soccer scores are represented in either of the
following forms:</p>
      <p>GER -:- USA</p>
      <p>GER 1:0 USA (16)
wherethefirstlinerepresentsagamenotyetplayedandthesecondoneagameinwhich
the digits are the goals scored by the adjacent team (a single digit suffices in practice).
The following operation parses scores:
parse (team1++" -:- "++team2) = (team1,team2,Nothing)
parse (team1++[’ ’,x,’:’,y,’ ’]++team2)
| isDigit x &amp;&amp; isDigit y (17)
= (team1,team2, Just(toInt x,toInt y))
parse - = error "Wrong format!"</p>
      <p>
        Example 5. The Dutch National Flag problem [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] has been proposed in a simple
form to discuss the termination of rewriting [
        <xref ref-type="bibr" rid="ref12">12</xref>
        ]. A formulation in Curry of this simple
form is equally simple:
dnf (x++[White,Red]++y) = dnf (x++[Red,White]++y)
dnf (x++[Blue,Red]++y) = dnf (x++[Red,Blue]++y) (18)
dnf (x++[Blue,White]++y) = dnf (x++[White,Blue]++y)
However, (18) needs a termination condition to avoid failure. With our proposed
semantics, this condition is simply:
(14)
(19)
dnf x = x
With the standard semantics, a much more complicated condition is needed.
      </p>
    </sec>
    <sec id="sec-5">
      <title>5 Implementation</title>
      <p>A good implementation of the proposed changes in the semantics of rule selection
requires new compilation schemes for Curry. However, an implementation can also be
obtained by a transformation over source programs when existing advanced features of
Curry are exploited. This approach provides a reference semantics that avoids
explicitly specifying all the details of our proposal, in particular, the subtle interplay between
condition solving and non-determinism and failures in arguments. Hence, we define
in this section a program transformation that implements our proposed changes within
existing Curry systems.</p>
      <p>
        Initially, we discuss the implementation of a single rule with a sequence of
conditions, i.e., a program rule of the form
(20)
According to our proposal, if the left-hand side l matches a call, the conditions
c1; : : : ; ck are sequentially evaluated. If ci is the first condition that evaluates to True,
all other conditions are ignored so that (20) becomes equivalent to
Note that the subsequent conditions are ignored even if the condition ci also
evaluates to False. Thus, the standard translation of rules with multiple guards, as defined in
the current report of Curry [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ], i.e., replacing multiple guards by nested if-then-else
constructs, would yield a non-intended semantics. Moreover, non-determinism and
failures in the evaluation of actual arguments must be distinguished from similar outcomes
caused by the evaluation of the condition, as discussed in Section 3.
      </p>
      <p>
        All these requirements call for the encapsulation of condition checking where
“inside” and “outside” non-determinism are distinguished and handled differently.
Fortunately, recent developments for encapsulated search in functional logic programming
[
        <xref ref-type="bibr" rid="ref10 ref6">6, 10</xref>
        ] provide an appropriate solution of this problem. For instance, [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ] proposes an
encapsulation primitive allValues so that the expression (allValues e) evaluates to the
set of values of e where only internal non-determinism inside e is considered. Thus, we
can use the following expression to check a condition c with our intended meaning:3
if notEmpty (allValues (solve c)) then e1 else e2
(21)
According to [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ], the meaning of this expression is as follows:
1. Test whether there is some evaluation of c to True.
2. If the test is positive, evaluate e1.
3. If there is no evaluation of c to True, evaluate e2.
      </p>
      <p>
        The semantics of allValues ensures that non-determinism and failures caused by
expressions not defined inside c, in particular, parameters of the left-hand side l of the
operation, are not encapsulated. The Curry implementations PAKCS [
        <xref ref-type="bibr" rid="ref15">15</xref>
        ] and KiCS2
[
        <xref ref-type="bibr" rid="ref8">8</xref>
        ] provide set functions [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ] instead of allValues which allows the implementation of
this conditional in a similar way.
3 [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ] defines only an operation isEmpty. Hence we assume that notEmpty is defined by the rule
notEmpty x = not (isEmpty x).
      </p>
      <p>Our expected semantics demands that a rule with a solvable condition be applied
for each true condition, in particular, with a possible different binding computed by
evaluating the condition. To implement this behavior, we assume an auxiliary operation
ifTrue that combines a condition and an expression. This operation is simply defined by
(22)
(23)
(24)
ifTrue True x = x
Then we define the meaning of (20) by the following transformation:
l = if notEmpty (allValues (solve c1))
. then (ifTrue c1 e1) else
.
.
if notEmpty (allValues (solve ck))</p>
      <p>then (ifTrue ck ek) else failed
There are obvious simplifications of this general scheme. For instance, if ck = True, as
frequently is the case, the last line of (23) becomes ek.</p>
      <p>
        This transformation scheme is mainly intended as the semantics of sequential
condition checking rather than as the final implementation (similarly to the specification of
the meaning of guards in Haskell [
        <xref ref-type="bibr" rid="ref20">20</xref>
        ]). A sophisticated implementation could improve
the actual code. For instance, each condition ci is duplicated in our scheme. Moreover,
it seems that conditions are always evaluated twice. However, this is not the case if a
lazy implementation of encapsulated search via allValues or set functions is used, as in
the Curry implementation KiCS2 [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ]. If ci is the first solvable condition, the emptiness
test for (allValues ci) can be decided after computing a first solution. In this case, this
solution is computed again (and now also all other solutions) in the then-part in order
to pass its computed bindings to ei. Of course, a more primitive implementation might
avoid this duplicated evaluation.
      </p>
      <p>Next we consider the transformation of a sequence of rules
l1 r1
.
.
.</p>
      <p>
        lk rk
where each left-hand side li is a pattern f pi1 : : : pini for the same function f and each
ri is a sequence of condition/expression pairs of the form “j c = e” as shown in (20).4
We assume that the pattern arguments pij contain only constructors and variables. In
particular, functional patterns have been eliminated by moving them into the condition
using the function pattern unification operator “=:&lt;=” (as shown in [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ]). For instance,
rule (1) is transformed into
fix int xs | (x ++ ".0") =:&lt;= xs = x
(25)
Finally, we assume that subsequent rules with the same pattern (up to variable
renaming) are joined into a single rule with multiple guards. For instance, the rules (2) can be
joined (after eliminating the functional pattern) into the single rule
4 In order to handle all rules in a unique manner, we consider an unconditional rule “li = ei” as
an abbreviation for the conditional rule “li | True = ei”.
      </p>
      <p>
        fix int xs
| (x ++ ".0") =:&lt;= xs = x
| True = xs
Now we distinguish the following cases:
– The patterns in the left-hand sides l1; : : : ; lk are inductively sequential [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ], i.e., the
patterns can be organized in a tree structure such that there is always a
discriminating (inductive) argument: since there are no overlapping left-hand sides in this
case, the order of the rules is not important for the computed results. Therefore, no
further transformation is necessary in this case. Note that most functions in typical
functional logic programs are defined by inductively sequential rules.
– Otherwise, there might be overlapping left-hand sides so that it is necessary to
check all rules in a sequential manner. For this purpose, we put the pattern matching
into the condition so that the patterns and conditions are checked together. Thus, a
rule like
      </p>
      <p>f p1 : : : pn | c = e
is transformed into
f x1 : : : xn | (\p1 : : : pn -&gt; c ) x1 : : : xn</p>
      <p>= (\p1 : : : pn -&gt; ifTrue c e) x1 : : : xn
where x1; : : : ; xn are fresh variables (the extension to rules with multiple
conditions is straightforward). Using this transformation, we obtain a list of rules with
identical left-hand sides which can be joined into a single rule with multiple guards,
as described above.</p>
      <p>
        For instance, the definition of fix int (26) is transformed into
fix int xs =
if notEmpty (allValues (solve (x++".0" =:&lt;= xs)))
then (ifTrue (x++".0" =:&lt;= xs) x) (27)
else xs
For an example of transforming rules with overlapping patterns, consider an operation
that reverses a two-element list and leaves all other lists unchanged:
rev2 [x,y] = [y,x]
rev2 xs = xs (28)
According to our transformation, this definition is mapped into (after some
straightforward simplifications):
rev2 xs =
if notEmpty (allValues (\[x,y] -&gt; True) xs)
then (\[x,y] -&gt; [y,x]) xs (29)
else xs
Thanks to the logic features of Curry, one can also use this definition to generate
appropriate argument values for rev2. For instance, if we evaluate the expression rev2 xs
(where xs is a free variable), the Curry implementation KiCS2 [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ] has a finite search
space and computes the following bindings and values:
fxs = []g []
fxs = [x1]g [x1]
fxs = [x1,x2]g [x2,x1]
fxs = (x1:x2:x3:x4)g (x1:x2:x3:x4)
As mentioned above, the transformation presented in this section is intended to serve
as a reference semantics for our proposed changes and to provide a prototypical
implementation. There are various possibilities to improve this implementation. For instance,
if the right-hand side expressions following each condition are always evaluable to a
value, i.e., to a finite expression without defined operations, the duplication of the code
of the condition as well as the potential double evaluation of the first solvable
condition can be easily avoided. As an example, consider the following operation that checks
whether a string contains a non-negative float number (without an exponent):
isNNFloat (f1 ++ "." ++ f2)
      </p>
      <p>
        | all isDigit f1 &amp;&amp; all isDigit f2 = True (30)
isNNFloat -= False
If c denotes the condition
(f1 ++ "." ++ f2) =:&lt;= s &amp;&amp;
all isDigit f1 &amp;&amp; all isDigit f2
by functional pattern elimination [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ], program (30) is equivalent to
isNNFloat s | c = True
isNNFloat - = False
Applying our transformation, we obtain the following code with the duplicated
condition c:
isNNFloat s =
if notEmpty (allValues (solve c))
then (ifTrue c True) (33)
else False
Since the expressions on the right-hand side are always values (True or False), we can
put these expressions into the sets computed by allValues. Then the check for a solvable
condition becomes equivalent to check the non-emptiness of these value sets so that we
return non-deterministically some value of this set.5 This idea can be implemented by
the following scheme which does not duplicate the condition and evaluates it only once
(the actual code can be simplified but we want to show the general scheme):
isNNFloat s =
      </p>
      <p>if notEmpty s1 then chooseValue s1 else False
where (34)
s1 = allValues (ifTrue c True)
Note that this optimization is not applicable if it is not ensured that the right-hand side
expressions are always evaluable to values. For instance, consider definition (28) of
5 The predefined operation chooseValue non-deterministically returns some value of a set.
(31)
(32)
rev2 and the expression head (rev2 [nv; 0]), where nv is an expression without a value
(e.g., failure or non-termination). With our current transformation (29), we compute
the value 0 for this expression. However, the computation of the set of all values of
(rev2 [nv; 0]) w.r.t. the first rule defining rev2 does not yield any set since the
righthand side [0; nv] has no value. This explains our transformation scheme (23) which
might look complicated at a first glance.</p>
      <p>However, there is another transformation to implement overlapping rules like (28)
with our intended semantics. If the rules are unconditional, one can “complete” the
missing constructor patterns in order to obtain an inductively sequential definition. For
the operation rev2, we obtain the following definition:
rev2 [x,y] = [y,x]
rev2 [] = []
rev2 [x] = [x] (35)
rev2 (x:y:z:xs) = x:y:z:xs
Since a case can be more efficiently executed than an encapsulated computation, this
alternative transformation might lead to larger but more efficient target code.
6</p>
    </sec>
    <sec id="sec-6">
      <title>Related Work</title>
      <p>Declarative programming languages support the construction of readable and reliable
programs by partitioning complex procedures into smaller units—mainly using case
distinction by pattern matching and conditional rules. Since we propose a new
interpretation of case distinctions for functional logic programs, we compare our proposal with
existing ones with similar objectives.</p>
      <p>
        The functional programming language Haskell [
        <xref ref-type="bibr" rid="ref20">20</xref>
        ] provides, similarly to Curry,
also pattern matching and guarded rules for case distinctions. Our proposal for a new
sequential interpretation of patterns increases the similarities between Curry and Haskell.
Although Curry provides more features due to the built-in support to deal with
nondeterministic and failing computations, our proposal is a conservative extension of
Haskell’s guarded rules, i.e., it has the same behavior as Haskell when non-determinism
and failures do not occur. To see this, consider a program rule with multiple conditions:
Since non-deterministic computations do not exist in Haskell and failures lead to
exceptions in Haskell, we assume that, if this rule is applied in Haskell to an
expression e, there is one condition ci which evaluates to True and all previous conditions
c1; : : : ; ci 1 evaluate to False. If we consider the same rule translated with the
transformation scheme (23), obviously each condition notEmpty (allValues (solve cj )) reduces
to False for j = 1; : : : ; i 1 and to True for j = i. Thus, the application of this rule
reduces e to (ifTrue ci ei) and, subsequently, to ei, as in Haskell.
      </p>
      <p>
        The logic programming language Prolog [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ] also supports pattern matching and,
for sequential conditions, an if-then-else construct of the form “c -&gt; e1 ; e2”.
Although Prolog can deal, similarly to Curry, with non-deterministic and failing
computations, the if-then-else construct usually restricts the completeness of the search space
due to cutting the choice points created by c before executing e1. Hence, only the first
solution of c is used to evaluate e1. Furthermore, inside and outside non-determinism
is not distinguished so that variables outside the condition c might be bound during its
evaluation. This has the effect that predicates where if-then-else is used are often
restricted to a particular mode. For instance, consider the re-definition of rev2 (28) as a
predicate in Prolog using if-then-else:
rev2(Xs,Ys) :- Xs=[X,Y] -&gt; Ys=[Y,X] ; Ys=Xs.
(37)
If we try to solve the goal rev2(Xs; Ys), Prolog yields the single answer Xs = [A; B],
Ys = [B; A]. Thus, in contrast to our approach, all other answers are lost.
      </p>
      <p>
        Various encapsulation operators have been proposed for functional logic programs
[
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] to encapsulate non-deterministic computations in some data structure. Set
functions [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ] have been proposed as a strategy-independent notion of encapsulating
nondeterminism to deal with the interactions of laziness and encapsulation (see [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] for
details). We can also use set functions to distinguish successful and non-successful
computations, similarly to negation-as-failure in logic programming, exploiting the
possibility to check result sets for emptiness. When encapsulated computations are nested
and performed lazily, it turns out that one has to track the encapsulation level in order to
obtain intended results, as discussed in [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ]. Thus, it is not surprising that set functions
and related operators fit quite well to our proposal.
      </p>
      <p>
        Computations with failures for the implementation of an if-then-else construct and
default rules in functional logic programs have been also explored in [
        <xref ref-type="bibr" rid="ref18 ref22">18, 22</xref>
        ]. In these
works, an operator, fails, is introduced to check whether every reduction of an
expression to a head-normal form is not successful. The authors show that this operator can be
used to define a single default rule, but not the more general sequential rule checking of
our approach. Moreover, nested computations with failures are not considered by these
works. As a consequence, the operator fails might yield unintended results if it is used
in nested expressions. For instance, if we use fails instead of allValues to implement the
operation isUnit defined in (12), the evaluation of isUnit failed yields the value False in
contrast to our intended semantics.
7
      </p>
    </sec>
    <sec id="sec-7">
      <title>Conclusions</title>
      <p>We proposed two changes to the current design of Curry. The first one concerns the
removal of the type Success and the related constraint equality “=:=”. This simplifies
the language since it relieves the programmer from choosing the appropriate equality
operator. The second one concerns a strict order in which rules and conditions are tried
to reduce an expression. This makes the language design more similar to functional
languages like Haskell so that functional programmers will be more comfortable with
Curry. Nevertheless, the logic programming features, like non-determinism and
evaluating functions with unknown arguments, are still applicable with our new semantics.
This distinguishes our approach from similar concepts in logic programming which
simply cuts alternatives.</p>
      <p>However, our proposal comes also with some drawbacks. We already mentioned
that in knowledge-based or constraint programming applications, a sequential ordering
of rules is not intended. Hence, a compiler pragma could allow the programmer to
choose between a sequential or an unordered interpretation of overlapping rules.</p>
      <p>
        A further drawback of our approach concerns the run-time efficiency. We argued
that solving “==” equations by narrowing with standard equational rules can replace
the constraint equality “=:=”. Although this is true from a semantic point of view,
the constraint equality operator “=:=” is more efficient from an operational point of
view. If x and y are free variables, the equational constraint “x=:=y” is
deterministically solved by binding x to y (or vice versa), whereas the Boolean equality “x==y” is
solved by non-deterministically instantiating x and y to identical values. The efficiency
improvement of performing bindings is well known, e.g., it is benchmarked in [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ] for
the Curry implementation KiCS2. On the other hand, the Boolean equality “x==y” is
more powerful since it can also solve negated conditions, i.e., evaluate “x==y” to False
by binding x and y to different values.
      </p>
      <p>Hence, for future work it is interesting to find a compromise, e.g., performing
variable bindings when “x==y” should be reduced to True without any surrounding
negations. A program analysis could be useful to detect such situations at compile time.</p>
      <p>
        Finally, the concurrency features of Curry must be revised. Currently, concurrency is
introduced by the concurrent conjunction operator “&amp;” on constraints. If the constraint
type Success is removed, other forms of concurrent evaluations might be introduced,
e.g., in operators with more than one demanded argument (“==”, “+”,. . . ), explicit
concurrent Boolean conjunctions, or only in the I/O monad similarly to Concurrent Haskell
[
        <xref ref-type="bibr" rid="ref21">21</xref>
        ].
      </p>
      <p>Despite all the drawbacks, our proposal is a reasonable approach to simplify the
design of Curry and make it more convenient for the programmer.
8</p>
    </sec>
    <sec id="sec-8">
      <title>Acknowledgments</title>
      <p>This material is based upon work partially supported by the National Science
Foundation under Grant No. CCF-1317249.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <surname>H.</surname>
          </string-name>
          <article-title>A¨ıt-Kaci and</article-title>
          <string-name>
            <given-names>A.</given-names>
            <surname>Podelski</surname>
          </string-name>
          .
          <article-title>Towards a meaning of LIFE</article-title>
          .
          <source>In Proc. of the 3rd Int. Symposium on Programming Language Implementation and Logic Programming</source>
          , pages
          <fpage>255</fpage>
          -
          <lpage>274</lpage>
          . Springer LNCS 528,
          <year>1991</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <given-names>S.</given-names>
            <surname>Antoy</surname>
          </string-name>
          .
          <article-title>Definitional trees</article-title>
          .
          <source>In Proc. of the 3rd International Conference on Algebraic and Logic Programming</source>
          , pages
          <fpage>143</fpage>
          -
          <lpage>157</lpage>
          . Springer LNCS 632,
          <year>1992</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <given-names>S.</given-names>
            <surname>Antoy</surname>
          </string-name>
          .
          <article-title>Optimal non-deterministic functional logic computations</article-title>
          .
          <source>In Proceedings of the Sixth International Conference on Algebraic and Logic Programming (ALP'97)</source>
          , pages
          <fpage>16</fpage>
          -
          <lpage>30</lpage>
          , Southampton, UK,
          <year>September 1997</year>
          . Springer LNCS 1298. Extended version at http: //cs.pdx.edu/ antoy/homepage/publications/alp97/full.pdf.
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <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>Declarative programming with function patterns</article-title>
          .
          <source>In Proceedings of the International Symposium on Logic-based Program Synthesis and Transformation (LOPSTR'05)</source>
          , pages
          <fpage>6</fpage>
          -
          <lpage>22</lpage>
          . Springer LNCS 3901,
          <year>2005</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <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>Overlapping rules and logic variables in functional logic programs</article-title>
          .
          <source>In Proceedings of the 22nd International Conference on Logic Programming (ICLP</source>
          <year>2006</year>
          ), pages
          <fpage>87</fpage>
          -
          <lpage>101</lpage>
          . Springer LNCS 4079,
          <year>2006</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          6.
          <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>Set functions for functional logic programming</article-title>
          .
          <source>In Proceedings of the 11th ACM SIGPLAN International Conference on Principles and Practice of Declarative Programming (PPDP'09)</source>
          , pages
          <fpage>73</fpage>
          -
          <lpage>82</lpage>
          . ACM Press,
          <year>2009</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7.
          <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>
          , and
          <string-name>
            <given-names>F.</given-names>
            <surname>Huch</surname>
          </string-name>
          .
          <article-title>Encapsulating non-determinism in functional logic computations</article-title>
          .
          <source>Journal of Functional and Logic Programming</source>
          ,
          <source>2004(6)</source>
          ,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <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>
            <surname>B.</surname>
          </string-name>
          <article-title>Peemo¨ller, and</article-title>
          <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="ref9">
        <mixed-citation>
          9.
          <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>
            <surname>B.</surname>
          </string-name>
          <article-title>Peemo¨ller, and</article-title>
          <string-name>
            <given-names>F.</given-names>
            <surname>Reck</surname>
          </string-name>
          .
          <article-title>Implementing equational constraints in a functional language</article-title>
          .
          <source>In Proc. of the 15th International Symposium on Practical Aspects of Declarative Languages (PADL</source>
          <year>2013</year>
          ), pages
          <fpage>125</fpage>
          -
          <lpage>140</lpage>
          . Springer LNCS 7752,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          10.
          <string-name>
            <surname>J. Christiansen</surname>
            ,
            <given-names>M.</given-names>
          </string-name>
          <string-name>
            <surname>Hanus</surname>
            ,
            <given-names>F.</given-names>
          </string-name>
          <string-name>
            <surname>Reck</surname>
            , and
            <given-names>D.</given-names>
          </string-name>
          <string-name>
            <surname>Seidel</surname>
          </string-name>
          .
          <article-title>A semantics for weakly encapsulated search in functional logic programs</article-title>
          .
          <source>In Proc. of the 15th International Symposium on Principle and Practice of Declarative Programming (PPDP'13)</source>
          , pages
          <fpage>49</fpage>
          -
          <lpage>60</lpage>
          . ACM Press,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          11.
          <string-name>
            <given-names>P.</given-names>
            <surname>Deransart</surname>
          </string-name>
          , A. Ed-Dbali, and
          <string-name>
            <given-names>L.</given-names>
            <surname>Cervoni</surname>
          </string-name>
          .
          <article-title>Prolog - the standard: reference manual</article-title>
          . Springer,
          <year>1996</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          12.
          <string-name>
            <given-names>N.</given-names>
            <surname>Dershowitz</surname>
          </string-name>
          .
          <article-title>Termination of rewriting</article-title>
          .
          <source>J. Symb. Comput.</source>
          ,
          <volume>3</volume>
          (
          <issue>1</issue>
          /2):
          <fpage>69</fpage>
          -
          <lpage>116</lpage>
          ,
          <year>1987</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          13.
          <string-name>
            <given-names>E.W.</given-names>
            <surname>Dijkstra</surname>
          </string-name>
          .
          <article-title>A Discipline of Programming</article-title>
          . Prentice-Hall,
          <year>1976</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          14.
          <article-title>The JSON Data Interchange Standard</article-title>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          15.
          <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>
            , K. Ho¨ppner, J. Koj,
            <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="ref16">
        <mixed-citation>
          16. 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="ref17">
        <mixed-citation>
          17.
          <string-name>
            <given-names>J.</given-names>
            <surname>Lloyd</surname>
          </string-name>
          .
          <article-title>Programming in an integrated functional and logic language</article-title>
          .
          <source>Journal of Functional and Logic Programming</source>
          ,
          <year>1999</year>
          (3):
          <fpage>1</fpage>
          -
          <lpage>49</lpage>
          ,
          <year>1999</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          18.
          <string-name>
            <given-names>F.J.</given-names>
            <surname>Lo</surname>
          </string-name>
          <article-title>´pez-Fraguas and</article-title>
          J.
          <string-name>
            <surname>Sa</surname>
          </string-name>
          <article-title>´nchez-Herna´ndez. A proof theoretic approach to failure in functional logic programming</article-title>
          .
          <source>Theory and Practice of Logic Programming</source>
          ,
          <volume>4</volume>
          (
          <issue>1</issue>
          ):
          <fpage>41</fpage>
          -
          <lpage>74</lpage>
          ,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          19.
          <string-name>
            <given-names>G.</given-names>
            <surname>Orwell. Animal Farm</surname>
          </string-name>
          :
          <string-name>
            <given-names>A Fairy</given-names>
            <surname>Story</surname>
          </string-name>
          .
          <source>Secker and Warburg</source>
          , London, UK,
          <year>1945</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref20">
        <mixed-citation>
          20. 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="ref21">
        <mixed-citation>
          21.
          <string-name>
            <given-names>S.L. Peyton</given-names>
            <surname>Jones</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Gordon</surname>
          </string-name>
          , and
          <string-name>
            <given-names>S. Finne. Concurrent</given-names>
            <surname>Haskell</surname>
          </string-name>
          .
          <source>In Proc. 23rd ACM Symposium on Principles of Programming Languages (POPL'96)</source>
          , pages
          <fpage>295</fpage>
          -
          <lpage>308</lpage>
          . ACM Press,
          <year>1996</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref22">
        <mixed-citation>
          22.
          <string-name>
            <surname>J. Sa</surname>
          </string-name>
          <article-title>´nchez-Herna´ndez. Constructive failure in functional-logic programming: From theory to implementation</article-title>
          .
          <source>Journal of Universal Computer Science</source>
          ,
          <volume>12</volume>
          (
          <issue>11</issue>
          ):
          <fpage>1574</fpage>
          -
          <lpage>1593</lpage>
          ,
          <year>2006</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref23">
        <mixed-citation>
          23.
          <string-name>
            <given-names>J.R.</given-names>
            <surname>Slagle</surname>
          </string-name>
          .
          <article-title>Automated theorem-proving for theories with simplifiers, commutativity, and associativity</article-title>
          .
          <source>Journal of the ACM</source>
          ,
          <volume>21</volume>
          (
          <issue>4</issue>
          ):
          <fpage>622</fpage>
          -
          <lpage>642</lpage>
          ,
          <year>1974</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>