- [ ] Improve `cast’ function (n-ary functions)
- [ ] Change n-ary to n partial applications
- [ ] Type Checker for $λ→\langle τ \rangle$
- [ ] Change
~
to work with pair and->n
types - [ ] Custom Reader
- [ ] Read Scheme files
- [ ] Cast, Type Check
- [ ] Send to compiler :
cf
- [ ] Handle REPL
system-global-environment ; use for redefining stuff
(the-environment) ; needs to be called. use inside functions/macros (at top level)
; i.e. bind inside a `let' fist
(nearest-repl/environment) ; needs to be called.
Get value from the environment
(define *symbol* (environment-lookup system-global-environment 'symbol))
(define-syntax symbol
...)
fixnum
: an integer constant. e.g.1
ratnum
: a rational constant e.g.(/ 1 2)
flonum
: a floating point constant e.g.1.0
recnum
: a complex number e.g.3+4i
string
: a string e.g.("H")
character
: a character e.g.#\c
pair
: a cons cell e.g.(1 . 2)
list
: a cons cell ending with the empty list e.g(1 2)
procedure
: a lambda expression e.g.(lambda (x) x)
interned-symbol
: a symboluninterned-symbol
: a fresh symbol guaranteed to not exist in the environment
The expression is evaluated
(dispatch-tag expr)
(dispatch-tag-contents (dispatch-tag expr)) ; to view the contents
quote
is used to stop evalution.
(define-syntax no-eval
(syntax-rules ()
((_ expr)
(quote expr))))
linear-match.scm
contains the pattern matcher found at http://okmij.org/ftp/Scheme/macros.html#match-case-simple
Each pattern is required to have a guard. ()
is the empty guard.
(,x)
represents a variable. Will be bound as x
if matched.
Examples
(define (sum-list ls)
(match ls
(() () 0) ; match with empty list
((,x . ,xs) (number? x) (+ x (sum-list xs)))))
All of this can be found in the file first.scm
Implements the following rules
(define (~ type1 type2)
(cond ((or (any-type? type1) (any-type? type2)) #t)
((equal? type1 type2) #t)
((and (pair? type1) (pair? type2))
(and (~ (car type1) (car type2))
(~ (cdr type1) (cdr type2))))
(else #f)))
All of this can be found in the file first.scm
Implements the typing rule
The typed-lambda
form simply evaluates to a lambda
expression for now.
Later on, we will want to use type-check
on the expression first.
Examples of typed-lambda
(define inc (typed-lambda (: x 'number) (+ x 1)))
(define len
(typed-lambda (: x 'list)
(if (null? x)
0
(+ 1 (len (cdr x))))))
(define apply-func
(typed-lambda (: f '(-> any any))
(typed-lambda (: x 'any)
(f x))))
(define (type-check expr type gamma)
(match expr
... ; Lot more here
(('typed-lambda (: ,x ,s) ,body) (arrow-type? type)
(if (not (~ s (domain type)))
(error "Inconsistent parameter type -- " s 'with (domain type))
(let ((param-type s))
(make-arrow param-type
(type-check body
(codomain type)
(cons (cons x param-type) gamma))))))
(__ () (error "Type checking failed -- " expr 'with type))))
(->n number number)
(-> number (-> boolean any))
(->2 number boolean)
(-> (* number number) boolean)
(-> (* number boolean) string)
Will have to rethink these rules. Approach now is to first cast Scheme expressions and then type-check
The following passes the current type checker.
(type-check '((typed-lambda (:: x number) (+ x 1)) "H") 'any '())
There doesn’t seem to be a straightforward way to add the typed-lambda
expression to
the type environment (()
here). Took a look at the main paper again, and it seems like
casting is one way this issue can be avoided.
This is probably the approach we should take. It is also the one described in “Gradual Typing for Functional Languages”
For right now, we’ll implement the following rules.
Rule for variables. any
type
as a default.
Rule for predefined types and constants. Think +
, *
, >
, <
, and so on
Rule for
Rule for application. The rules depend on the information available in
Will look something like this
(define (cast e Γ)
(pmatch expr
(,e (guard (symbol? e)) `(: e (lookup Γ e)))
((λ (: ,x ,type) ,body) `(λ (: x type) (cast body (extend Γ x type))))
((,e1 . ,e2) ... rules for application)))
The cast
function should be idempotent.
Syntax is (: <expr> <type>)
(castu '(fn (: x number) x) '())
=> (: (fn (: x number) (: x number)) (-> number number))
(castu '(f x) '())
=> (: ((: f (-> any any)) (: x any)) any)
(castu '(f x) '((x . number)))
=> (: ((: f (-> number any)) (: x number)) any)
(castu '(is-zero? x) '((is-zero? . (-> number boolean))))
=> (: ((: is-zero? (-> number boolean)) (: x number)) boolean)
(castu '(f (x y)) '())
=> (: ((: f (-> any any)) (: ((: x (-> any any)) (: y any)) any)) any)
(castu '((f x) y) '())
=> (: ((: ((: f (-> any any)) (: x any)) (-> any any)) (: y any)) any)
fun x -> x x;;
(* This expression has type 'a -> 'b but an expression was
expected of type 'a. The type variable 'a occurs inside 'a -> 'b *)
(lambda (x) (x x))
;; Type Checker: missing type for identifier;
(lambda ([x : (-> Any Any)]) (x x))
;; - : (-> (-> Any Any) Any)
(lambda ([x : (-> Any Any)]) (x (x x)))
;; - : (-> (-> Any Any) Any)
fun f x -> f (f x);;
(* : - : ('a -> 'a) -> 'a -> 'a = <fun> *)
(lambda ([f : (-> Any Any)] [x : Number]) (f (f x)))
;; - : (-> (-> Any Any) Number Any)
(lambda (f x) (f (f x)))
;; Type Checker: Cannot apply expression of type Any,
;; since it is not a function type
fun x -> if x > 0 then 1 else false;;
(* Error: This expression has type bool but an expression was expected of type int *)
(lambda ([x : Real]) (if (> x 0) 1 #f))
;; - : (-> Real (U False One))
[1; false; "string"];;
(* This expression has type bool but an expression was expected of type int *)
'(1 #f "string")
;; - : (Listof (U False One String)) [mode precisely: (List One False String)]
Can write a function that performs self application, but we don’t get anything we can use from it
(define self-app (lambda ([x : (-> Any Any)]) (x x)))
(define iden (lambda (x) x))
(self-app iden) ; Type : Any ; Value : #<procedure:iden>
((self-app iden) 1) ; ERROR
Here is how it works in Scheme
(define self-app (lambda (x) (x x)))
(define iden (lambda (x) x))
(self-app iden) ; #<procedure>
((self-app iden) 1) ; 1
(lambda ([f : (-> Any Any)] [x : Number])
(f (f x)))
;; (-> (-> Any Any) Number Any)
(lambda ([f : (-> Any Number)] [x : Number])
(f (f x)))
;; (-> (-> Any Number) Number Number)
(lambda ([f : (-> Number Any)] [x : Number])
(f (f x)))
;; type mismatch, expected : Number, given : Any