guile-devel
[Top][All Lists]

## Typechecking I

 From: Stefan Israelsson Tampe Subject: Typechecking I Date: Tue, 16 Nov 2010 00:10:53 +0100 User-agent: KMail/1.13.5 (Linux/2.6.34.7-0.5-desktop; KDE/4.4.4; x86_64; ; )

```Hi,

Ok, here is a first step to analyse code.

Note,
attached to the mail is a modul /put it at a suitable place and fixup the
reference for the module. Then use e.g. (check '(if 1 1 1)) and you will get
the output you see further down in the email.

We will assume that local variables in the following is gensymed to be unique
and no name clashes apear.

For typechecking i find it interesting to consider an equational approach
first. e.g. translate code to an equation system.

let's take a first simple step here and and assume that the typecheck function
just finds the equation we need to solve in order to understand type
consistency and discovery. we will assume that typecheck is of the form
(typecheck Eq Code Type) or in short
Eq     is current equational state,
Code   the code to draw equations out of.
Type   the type associated with the result of Code

******************* Item I *******************************
[let X Y Z] : T

Translates to
(typecheck (typecheck Eq Y X) Z T)

Example of equation generation:
(let x 1 x):
((= integer x) (= x Texp))

(let x 1 (let y x y)):
((= integer x) (= x y) (= y Texp))

TODO: Note: (= y x) should be more nicer for the understanding!!!

This is not earthshaken. But I think it is wise to handle first such an
translational step in order to write a solver in kanren or prolog or racklog
or guilelog :-) for the more general case.

******************* Item II ***************************
[begin x ... xx] : T

(typecheck x e) o ... o (typecheck xx T)

the symbol e will mean an anything object so that essentially [= e x] is true
for all x. You could say everything that we have not assigned a type to has
type e and then (the idea) is that the all scheme expression should
typecheck. It remains to define the properties and rules associated with e to
make this work. The target is to be able to gradually mix typed expressions
with untyped expression.

Example:
(begin 1 "a" 1):
((= integer  e)
(= string   e)
(= integer  Texp))

******************* Item III ****************************
[lambda [x ...] code]

What to look up for here is that essentialle every usage of a lambda inside
a function has to, to be general, have a unique set of equations and do a
unique deduction. This can be expensive, but is the correct way to treat the
typechecking of the lambda. So we must tell the solver later on that we are
going to treat a lambda, e.g. x ... will be a unique version at every usage
of the lambda the directive for the solver is (lambda vars res equation)
lambda conceptually translates to an abstraction of an equations.

Example
(lambda (x y) x):
((= (lambda (x y) Tlam6583
((= x Tlam6583))) Texp))

********************** Item IV **************************
[apply f [x ...]] : T

First of all we need to deduce the equation of f, to yield a lambda. e.g.
(typecheck f [lamda [ArgType(x) ...] ResType]) o
(typecheck x [arg ArgType(x)]                ) o ... o

so
1. define the functional signatur.
2. find the equations typececked to [arg X], arg is a directive to the solver
to tell it that we are equating a function argument why? well the equality
needs to be treated differnetly in order to be correct.
3. the same reason for the addition of the last equation. we need to inform
the
solver that ResType is of a result type.

Example:
(apply (lambda (x y) x) (1 2)) :
((= (lambda (x y) Tlam6954 ((= x Tlam6954)))   ;; a lambda type abstraction
(lambda (Targ6951 Targ6952) Tres6953))     ;; a lambda type
(= integer (arg Targ6951))
(= integer (arg Targ6952))
(= (res Tres6953) Texp))

Can you see how res and arg differ
(= T (arg (or A B C)))   ; argument can be A or B or C
(= T (res (or A B C)))   ; function produces A or B or C

**************** Item V *************
[if P X Y] : T

(integer? X) makes a promise that if true then X is an integer and
is a string. Consider (= (res A) (arg integer)) if the result of a function
is anything it follows that it can't unify with an argument that has to
take an inte integer as in the case
(+ (g X) 1) and g is not typehcecked and we cannot ussume anything
about it hence the typecheck should fail. On the other hand
(if (integer? (g X)) (+ (g X) 1) #f) should be able to typecheck
against (or integer boolean) and here we would have an equality of the
type (= (validated integer) (res A)) and then A=integer in the rest of the
equations in the or.

Example:
(let x 1 (if (integer? x) "a" 2))
=================================
(= integer x)
(or ((=  x (validated integer)) (= string Texp))
((=  x (validated (not integer)))
(=  integer Texp))))

So maybe it's an unessesary step but at least I appriciate this little
transformation to get an understanding the subject. I'll will now work
a little with solving the equations.

And yes, all tree-il is not included, but I fix the complexity at this level
and move over to solving the equations.

Play around and have fun
/Stefan

``` equationalize.scm
Description: Text Data