This rule does not hold for certain special forms. Examples of special forms we have seen so far are:
\x. x*x
is an example of the
lambda abstraction special form. We can think of this as having a
pattern described by:
\ formals . bodyYou can think of this as evaluating to itself, with a rule for applying it to arguments (strip off \ and formals and substitute...) In the Lambda Calculus, there is only ONE special form, namely lambda abstraction. Having a small number of special forms is mathematically desirable, since the number of different cases to consider in mathematical analysis is reduced. However, in creating a practical programming language, certain other special forms are usually introduced. Where possible, these are made exactly equivalent to forms that can be expressed just using the Lambda Calculus.
Definition variable = expression End;This special form evaluates the expression and
if condition then expr1 else expr2 end if
It evaluates condition. If condition evaluates to true the result is obtained by evaluating expr1. If condition evaluates to false then the result of the if expression is obtained by evaluating expr2.
In POP2000 it is an error for the condition to evaluate to anything other than true or false.
[WHY does it have to be a special form? Could it NOT be a special form? ].
An isolated POP2000 identifier can be quoted, for example 'a. As such, it is called a symbol, and is a member of one of the basic datatypes of POP2000.
'CaT'is a symbol distinct from
'cat'
This reflects the fact that in POP2000 case is significant, as it is in C, but not in Scheme or Pascal.
expr.symbolis an expression exactly equivalent to expr 'symbol'. Why does the language support this minor syntactic variant? This was done to provide syntactic continuity between POP2000 classes, which are functions mapping from symbols to values and constructs of other languages (Java, SML, Modula...) which play a similar role, though with a more restricted semantics.
Boolean,Char,Null,Number,Pair, Procedure,String,Symbol,Vector,Application,TheoremWith each of these basic types there is associated a class. In POP2000 a class is a function which provides a basic collection of capabilities for recognising, creating and manipulating members of a type or types. Each type-name above has a corresponding class-variable which is bound to a class-function which provides basic support for members of that type, so that Boolean is the class-function associated with the type Boolean. To recognise whether a particular datum d belongs to a given type, we have the following construct Class . ? d
Boolean.? d is d a boolean? Char.? d is d a character? Composite.? d is d a composite expression? Null.? d is d null? Number.? d is d a number? Pair.? d is d a pair? Procedure.? d is d a procedure, that is a function object. String.? d is d a string, e.g. `the fat cat` Symbol.? d is d a symbol, e.g. 'x' Theorem.? d is d a the member of type Theorem? Vector.? d is d a vector of values, e.g. {2,3,4}You will doubtless recall that the form Class.? is shorthand for for Class '?'.
For any Class, the expression Class.? is a predicate for recognising members of that class.
There is a convention in POP2000 that identifiers beginning with an upper-case letter are the names of classes (a concept related to type). The predicates listed above, which recognise members of the basic types of POP2000 which do not overlap, that is for a given datum d, Class.? d will only evaluate to true for precisely one of the basic classes. There may be others basic types, e.g. files, and, in some environments, the widgets or windows which support graphical user interfaces.
The POP2000 language system "knows" quite a lot about the types of data that the built-in functions can operate on, and is able to detect certain errors as you compile code you have written. For example if you try to compile
Definition funny = \x. x + (y>z) Endyou will get an error message, because the system knows that y > z is a boolean, and you can't do arithmetic on a boolean. POP2000 has a limited built-in ability to infer the types which a user-defined function can manipulate.
Int Fixed precision integers, at least 30 bits of precision Integer Arbitrary precision integers. Rational Float Double ComplexIf "<" means "set inclusion", then the following hold:
Int < Integer < Rational < Number Float < Number Double < Number Complex < NumberThese inclusion relations are necessitated by closure requirements. The sum of the rationals 1/2+1/2 is the integer 1, so the set of POP2000 Integers actually must be included in the POP2000 rationals. This is not true of the Float type - the sum 0.5+0.5 is the Float 1.0, and not the integer 1.
+ - * /There are also the usual algebraic and trancendental functions. They operate on integers, rationals, floating-point representation of reals, complex numbers. Try:
sqrt -1;the answer is the complex number:
0.0+1.0iComparisons between numbers are denoted by the conventional symbols.
< > <= >=
0! = 1 n! = n(n-1)!These translate into POP2000 as follows:
Definition factorial = \n. if n=0 then 1 else n*factorial(n-1) end if End; factorial 5; 120Try evaluating factorial 1000 , and factorial 1000 / factorial 999 .
[1,2,3,4]is a list.
Null.?recognises the empty list. It is an error to apply the functions front or back to the empty list.
front []; Error: PAIR NEEDED Culprits: (), In file: /users/users3/fac/pop/poplocal/local/POP2000/lean3.lam Calling sequence: front This error report was prepared for Robin Popplestone by Jeremiah Jolt, your compile-time helper.
cons x ymakes a list whose front is x and whose back is y . So to make a list containing just the number 23 we do:
cons 23 [] [23]Now let's define a function to make a "sandwich" list:
Definition sandwich = \ x y. cons x (cons y (cons x [])) End;This could be written, equivalently but more conveniently, as
Definition sandwich = \ x y. [x,y,x] End;So:
sandwich 1 2;
evaluates to:
[1, 2, 1]
front (cons x y) = x back (cons x y) = y
We can't use the theorem type until we have a considerably more sophisticated understanding of the language, but in essence a theorem is a statement that is guaranteed to be true in a correctly implemented POP2000 system.
As an example, the theorem
|- All x y. front (cons x y) = xfollows immediately from the built-in axioms of POP2000.
The only theorem-constructing functions available in POP2000 are guaranteed to create valid theorems. So, the predicate-call
Theorem.? xis not asking if x is true - it's asking if x is a member of the type Theorem. If it is it's guaranteed to be true - the good news. The bad news is that the built-in functions for constructing theorems only make very simple steps in proof. So that it is not easy or automatic to make theorems of any profundity.
The Class concept in POP2000 has some superficial syntactic resemblence to the Class concept of Java and the structure and type concepts of SML. It differs from both these language in that POP2000 classes are first-class objects. In Java a class cannot be the value of a variable of the language. Likewise in SML a class can only be the value of a compile-time variable in a functor.
The built-in type-inference of POP2000 is much more restricted than is the Hindley-Milner type system of SML. However, this deficiency is made up for by the existence of theorems, which, following Milner, are a data-type all of whose members are guaranteed to express facts valid in a correctly-implemented POP2000 system.
Our approach to theorem-proving is not foundational, since there is a rich set of axioms which say, for example, that POP2000 contains a correctly implemented representation of the integers. In this we differ from the HOL system, which creates its theories from very the simple foundation of the lambda-calculus itself.