implement type inference
Two things out of one mechanism. `_' as a type means "work it out from
the initializer", so (var n _ (strlen s)) stops needing size-t spelled
out; `type-of' hands a macro the type of an expression, so a macro can
dispatch on what it was handed rather than on what was declared. Both
read the same answers from two sides.
Algorithm W's core, intra-procedural, with the extensions C forces:
- an unknown type, since (include stdio.h) brings in names we never
parsed. Unification is consistency rather than equality, so
anything touching an unparsed declaration stops constraining
instead of rejecting a program that compiled yesterday;
- the usual arithmetic conversions, since `+' is not a function of
one type;
- checking mode for initializers, since #(0 0) has no type of its own
and takes one from its context. #(T : ...) is the way out of that.
What it wanted on the way:
- what type a *name* has, which neither the typedef nor the tag
database recorded. One table serves functions and variables, since
a function type already has a surface spelling;
- a scope chain, so a (var c int 9) inside a do ends with the block;
- form-type, keyed by cons cell, so one form has one type;
- macros expanded during the walk rather than before it, so type-of
is answered in the scope the macro was written in.
Closures take the same machinery: a receiver whose type comes from a
call, captures written (name expr) and typed from the expression, and
conversion from a bare function wherever a closure is expected.
type-match grew `_' on the pattern side, since (closure ((int)) int)
and (closure ((float)) int) were separate clauses for one case.
This commit is contained in:
@@ -6,7 +6,11 @@
|
||||
"From an array: 1 2 3"
|
||||
"Index evaluated once: 21 i 1"
|
||||
"Through a struct member: 8"
|
||||
"Nested: 33")
|
||||
"Shadowed in a block: 9 then 15"
|
||||
"Nested: 33"
|
||||
"Named capture: 7"
|
||||
"Captured pointer: 11 then 12"
|
||||
"From a bare fn: 20 42 7")
|
||||
(return 0)
|
||||
|
||||
;;; A closure is a code pointer beside its captures, so what this
|
||||
@@ -22,6 +26,14 @@
|
||||
|
||||
(include stdio.h)
|
||||
|
||||
(fn double-it ((n int)) int
|
||||
(return (* n 2)))
|
||||
|
||||
;;; a bare function is a closure that captures nothing, so it converts
|
||||
;;; wherever one is expected -- here a declared return type
|
||||
(fn as-closure () (closure ((int)) int)
|
||||
(return double-it))
|
||||
|
||||
(fn make-adder ((n int)) (closure ((int)) int)
|
||||
(return (closure ((b int)) int (n)
|
||||
(return (+ n b)))))
|
||||
@@ -71,10 +83,39 @@
|
||||
(var h (struct handlers) #((struct handlers) : .on-tick (make-adder 5)))
|
||||
(printf "Through a struct member: %d\n" ((. h on-tick) 3))
|
||||
|
||||
;; a block opens a scope: the inner `add-10' ends with it, and the
|
||||
;; call after it is the closure again
|
||||
(do (var add-10 int 9)
|
||||
(printf "Shadowed in a block: %d then " add-10))
|
||||
(printf "%d\n" (add-10 5))
|
||||
|
||||
;; a closure built inside a closure, capturing that one's capture
|
||||
(var outer (closure ((int)) int)
|
||||
(closure ((x int)) int ()
|
||||
(var inner (closure ((int)) int) (make-adder x))
|
||||
(return (inner 3))))
|
||||
(printf "Nested: %d\n" (outer 30))
|
||||
|
||||
;; a capture can name what it holds rather than borrow a variable's
|
||||
;; name, and the expression is evaluated where the closure is written
|
||||
(var pt (struct handlers))
|
||||
(var sum-once (closure () int)
|
||||
(closure () int ((sum (+ 3 4))) (return sum)))
|
||||
(printf "Named capture: %d\n" (sum-once))
|
||||
|
||||
;; capturing a pointer is how by-reference is spelled; the caller owns
|
||||
;; what it points at
|
||||
(var counter int 11)
|
||||
(var peek (closure () int)
|
||||
(closure () int ((at (& counter))) (return (* at))))
|
||||
(printf "Captured pointer: %d then " (peek))
|
||||
(++ counter)
|
||||
(printf "%d\n" (peek))
|
||||
|
||||
;; ...and in an initializer, as an argument, and as a return
|
||||
(var from-fn (closure ((int)) int) double-it)
|
||||
(printf "From a bare fn: %d %d %d\n"
|
||||
(apply-twice from-fn 5)
|
||||
((as-closure) 21)
|
||||
(apply-twice (lambda ((n int)) int (return (+ n 1))) 5))
|
||||
(return 0))
|
||||
|
||||
Reference in New Issue
Block a user