Curry: An Integrated Functional Logic Language
Curry: An Integrated Functional Logic Language
Curry: An Integrated Functional Logic Language
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
this pattern that are not data constructors are considered as variables. For instance, the locally<br />
introduced identifiers a, b, l, and r in the previous examples are variables whereas the identifiers<br />
even and square denote functions. Note that this rule exclude the definition of 0-ary local functions<br />
since a definition of the form “where f = ...” is considered as the definition of a local variable<br />
f by this rule which is usually the intended interpretation (see previous examples). Appendix D.8<br />
contains a precise formalization of the meaning of local definitions.<br />
2.5 Free Variables<br />
Since <strong>Curry</strong> is intended to cover functional as well as logic programming paradigms, expressions<br />
(or constraints, see Section 2.6) might contain free (unbound, uninstantiated) variables. The idea<br />
is to compute values for these variables such that the expression is reducible to a data term or that<br />
the constraint is solvable. For instance, consider the definitions<br />
mother John = Christine<br />
mother Alice = Christine<br />
mother <strong>An</strong>drew = Alice<br />
Then we can compute a child of Alice by solving the equation (see Section 2.6)<br />
mother x =:= Alice. Here, x is a free variable which is instantiated to <strong>An</strong>drew in order to reduce<br />
the equation’s left-hand side to Alice. Similarly, we can compute a grandchild of Chistine by<br />
solving the equation mother (mother x) =:= Christine which yields the value <strong>An</strong>drew for x.<br />
In logic programming languages like Prolog, all free variables are considered as existentially<br />
quantified at the top-level. Thus, they are always implicitly declared at the top-level. In a language<br />
with different nested scopes like <strong>Curry</strong>, it is not clear to which scope an undeclared variable belongs<br />
(the exact scope of a variable becomes particularly important in the presence of search operators,<br />
see Section 8, where existential quantifiers and lambda abstractions are often mixed). Therefore,<br />
<strong>Curry</strong> requires that each free variable x must be explicitly declared using a declaration of the form<br />
x free. These declarations can occur in where-clauses or in a let enclosing a constraint. The<br />
variable is then introduced as unbound with the same scoping rules as for all other local entities<br />
(see Section 2.4). For instance, we can define<br />
isgrandmother g | let c free in mother (mother c) =:= g = True<br />
As a further example, consider the definition of the concatentation of two lists:<br />
append [] ys = ys<br />
append (x:xs) ys = x : append xs ys<br />
Then we can define the function last which computes the last element of a list by the rule<br />
last l | append xs [x] =:= l = x where x,xs free<br />
Since the variable xs occurs in the condition but not in the right-hand side, the following definition<br />
is also possible:<br />
last l | let xs free in append xs [x] =:= l = x where x free<br />
Note that the free declarations can be freely mixed with other local declarations after a let or<br />
where. The only difference is that a declaration like “let x free” introduces an existentially quan-<br />
9