# Correctness and completeness of eager and lazy semantics

In previous lecture we have seen two operational semantics for PCF, which is an extension of the lambda calculus. It is natural to ask what is the correspondence between the notion of beta reduction and these semantics, when restricted to the sub-language corresponding to the lambda calculus,

Theorem (Soundness of eager semantics) If M is a lambda term, and M eval N holds in the early semantics, then M ->> N (M beta-reduces to N).

The vice versa does not hold. Take for instance the term M = (\x y. y) P N, where P is any term whose evaluation does not terminate (for example, Y). We have that M beta-reduces to N, but, if the evaluation of P does not terminate, then the evaluation of M does not terminate either.

For the lazy semantics, on the contrary, also the other directions holds, at least in a weak form:

Theorem (Soundness and weak completeness of the lazy semantics) If M is a lambda term, and M eval N holds in the lazy semantics, then M ->> N holds. Viceversa, if M ->> N holds, then M eval P holds in the lazy semantics for some P such that P ->> N.

In the completeness part of the above theorem, in general N is different from P. Consider for instance M = \x. P, where P ->> Q. We have that M ->> \x. Q, but we cannot evaluate M to (\x. Q), since M is already in canonical form.

# Simulating lazy functions in eager languages

In a higher order eager language, it is in general possible to simulate lazy functions by encoding its arguments as abstractions (i.e. functions). In fact, abstractions are canonical forms, hence they are not evaluated.

For instance, we can encode streams and its constructors/selectors in ML as follows:

```   datatype 'a stream = empty | cons of 'a * (unit -> 'a stream);

fun tail (cons(a,f)) = f();
```
(we are obliged to use different names than ::, hd and tl, because the latter are reserved for the (eager) lists, which in ML are predefined). Now we can define function on streams in the usual way. For instance, the functions nats, times and facts of previous lecture can be defined as follows:
```   fun nats n = cons(n, fn() => nats(n+1));
fun times r s = cons((head r)*(head s), fn() => times (tail r) (tail s));
fun facts () = cons(1, fn () => times (facts ()) (nats 2));
```
(here we need to give an argument to facts only to satisfy the ML constraint on the syntax of functions.) Now, we can define, for instance
```   val s = facts();
```
The following are examples of interactions with ML (after giving the above definitions):
```   - head(tail s);
val it = 2 : int
val it = 6 : int
val it = 120 : int
```

# Lambda Prolog interpreters for the eager and the lazy semantics of PCF

We describe here a possible lambda Prolog implementation of the operational semantics of PCF.

## Syntax

The first step is representing the (abstract) syntax of PCF. Assuming that tm is the type of the lambda Prolog terms representing PCF terms, we need to define a function
[.] : PCF -> tm
We define [.] compositionally, introducing a new constructor each time we need it, in the following way:
[n] = c n (for n integer), where c : int -> tm
[true] = tt, where tt : tm
[false] = ff, where tt : tm
[M op N] = opp [M] [N], where for op = +, opp = plus : tm -> tm -> tm, etc.
[if M then N else P] = ite [M] [N] [P], where ite : tm -> tm -> tm -> tm
[(M,N)] = pair [M] [N] [P], where pair : tm -> tm -> tm
[fst M] = fst [M], where fst : tm -> tm
[snd M] = snd [M], where fst : tm -> tm
[M N] = app [M] [N], where app : tm -> tm -> tm
[\x.M] = ab (x\ [M]), where ab : (tm ->tm) -> tm
[let x = M in N] = let [M] (abs (x\[N])), where let : tm -> (tm -> tm) -> tm
[fix M] = fix [M], where fix : tm -> tm
[x] = x (for x variable)
Notes:
• In general for all the operators (like conditional, pairing etc.) we have the choice of encoding them as tm (and then using app) or as n-rary constructors. It seems reasonable to encode them as n-rary constructors since their semantics is different from the semantics of application.
• It would not be a good idea to encode [M N] as [M] [N]: first of all, we would have a type mismatch ([M] is of type tm, not tm -> tm). Second, and more important, the lambda Prolog semantics of [M] [N] might be different from the intended PCF semantics of M N.
• The encoding of \x.M uses the higher-order facilities of lambda Prolog. The definition [\x.M] = abs (x\ [M]) has the advantage that the term M[N/x] can then be encoded as (x\ [M]) [N]. The underlying beta-conversion mechanism of lambda Prolog will take care of performing the substitution (i.e. of replacing x by [N] in [M]).
• Since we are interested in evaluating only closed terms (open terms do not have a value), and we encode PCF abstractions as lambda Prolog abstractions, then the PCF variables have to be encoded as the lambda Prolog (abstraction) variables with the same name.
Below is the lambda Prolog module for representing the syntax of PCF
```   module PCF_Syntax.

%%% main syntactic category:

kind tm type.  % terms of PCF

%%% constructors for representing terms of Mini-ML.

type c int -> tm.                             % numerical constant
type tt, ff tm.                               % boolean constants
type plus, minus, times, dv tm -> tm -> tm.   % numerical ops
type equal tm.                                % comparison
type ite tm -> tm -> tm -> tm.                % conditional
type pair tm -> tm -> tm .                    % pairing
type fst, snd tm -> tm.                       % projections
type ab (tm -> tm) -> tm.                     % abstaction
type app tm -> tm -> tm.                      % application
type let tm -> (tm -> tm) -> tm.              % local declaration
type fix tm -> tm.                            % fixpoint operator
```

## Eager semantics

We want to define a predicate eval: tm -> tm -> o so that (eval M N) holds iff M evaluates to N in the system for the eager operational semantics. Here is a possible definition.
```   module PCF_eager_semantics.

import PCF_Syntax.

eval (c N) (c N).
eval tt tt.
eval ff ff.
eval (plus M N) (c X) :- eval M (c Y), eval N (c Z), X is Y + Z.
eval (minus M N) (c X) :- eval M (c Y), eval N (c Z), X is Y - Z.
eval (times M N) (c X) :- eval M (c Y), eval N (c Z), X is Y * Z.
eval (dv M N) (c X) :- eval M (c Y), eval N (c Z), X is Y div Z.
eval (equal M N) tt :- eval M (c Y), eval N (c Z), Y = Z.
eval (equal M N) ff :- eval M (c Y), eval N (c Z), (Y < Z ; Z < Y).
eval (ite M N P) V :- eval M tt , eval N V.
eval (ite M N P) V :- eval M ff , eval P V.
eval (pair M N) (pair V W) :- eval M V, eval N W.
eval (fst M) V :- eval M (pair V W).
eval (snd M) W :- eval M (pair V W).
eval (ab M) (ab M).
eval (app M N) V :- eval M (ab P) , eval N Q , eval (P Q) V.
eval (let M N) V :- eval M P, eval (N P) V.
eval (fix M) V :- eval M (ab N), eval (N (fix M)) V.
```

## Lazy semantics

This time we want eval: tm -> tm -> o to represent the lazy evaluation. Here is a possible definition.
```   module PCF_eager_semantics.

import PCF_Syntax.

eval (c N) (c N).
eval tt tt.
eval ff ff.
eval (plus M N) (c X) :- eval M (c Y), eval N (c Z), X is Y + Z.
eval (minus M N) (c X) :- eval M (c Y), eval N (c Z), X is Y - Z.
eval (times M N) (c X) :- eval M (c Y), eval N (c Z), X is Y * Z.
eval (dv M N) (c X) :- eval M (c Y), eval N (c Z), X is Y div Z.
eval (equal M N) tt :- eval M (c Y), eval N (c Z), Y = Z.
eval (equal M N) ff :- eval M (c Y), eval N (c Z), (Y < Z ; Z < Y).
eval (ite M N P) V :- eval M tt , eval N V.
eval (ite M N P) V :- eval M ff , eval P V.
eval (pair M N) (pair M N).
eval (fst M) V :- eval M (pair N P), eval N V.
eval (snd M) W :- eval M (pair N P), eval P V.
eval (ab M) (ab M).
eval (app M N) V :- eval M (ab P), eval (P N) V.
eval (let M N) V :- eval M P, eval (N P) V.
eval (fix M) V :- eval M (ab N), eval (N (fix M)) V.
```
Example of terms on which we can test eval:
```    type test int -> tm -> o.

%%% Test #1: term representing the factorial function:

test 1 (fix (ab (f\ ab (x\ ite (equal x (c 0))
(c 1)
(times x (app  f (minus x (c 1)))))))).

%%% Test #2: term representing factorial applied to 4

test 2 (F (c 4)) :- test 1 F.
```
We can for instance formulate the query
```    ?- test 2 M, eval M N.
```
which should return the solution N = (c 24).