Sheesh! This is the first post of year 2016… and it is April already! I worked on the ‘typed-language’ branch of Vicare, mostly on the expander. The typed language is moving forwards, step by step; there is still a lot to do.
Despite being called ‘typed-language’: I am using it as if it is the
master branch. This is bad. There have been so many changes that I hesitate
to merge it into the actual master
; I keep telling to myself: I have to do this
first, I have to do that first. Well… I will not merge it tomorrow, because I
have to do stuff first.
Everything I discuss here is relative to code in the head of the ‘typed-language’ branch.
When importing a module: it is now possible to use the full syntactic binding name modifiers. Example:
(module it (red blue) (define red 1) (define blue 2)) (define (doit) (import (prefix it private::)) (fprintf (current-error-port) "~a, ~a\n" private::red private::blue))
this should make modules usable as full namespace things, like in other languages.
Indeed, I have removed the ugly library (vicare language-extensions
namespaces)
(still there in the master
branch) because it is now useless.
The biggest development in the last four months is about type annotations: forms that
specify which type a variable has and a value is expected to have, when the typed
language is enabled. Simple type annotations where already present (I called them
tags before); in this example, the type annotation is the identifier
<string>
:
(define {O <string>} "ciao") (.length O) ⇒ 4
There are more now:
(is-a? "123" (or <false> <string>)) ⇒ #t (is-a? #f (or <false> <string>)) ⇒ #t (is-a? 99 (or <false> <string>)) ⇒ #f (is-a? 123 (and <fixnum> <positive>)) ⇒ #t (is-a? 123 (not <vector>)) ⇒ #t (is-a? '#(123) (not <vector>)) ⇒ #f (is-a? '(1 2 3) (list-of <positive-fixnum>)) ⇒ #t (is-a? '(1 "2") (list <fixnum> <string>)) ⇒ #t (is-a? '(1 "b" c) (pair <fixnum> (pair <string> (pair <symbol> <null>)))) ⇒ #t
there is also support for closure object’s signatures:
(type-annotation-super-and-sub? (lambda (<fixnum>) => (<fixnum>)) (lambda (<non-negative-fixnum>) => (<positive-fixnum>))) ⇒ #t
which will be useful in some future when I will attempt an implementation of interfaces. Unfortunately there is no way to validate the type of a closure object at run–time; this is problematic:
(is-a? display (case-lambda ((<top>) => (<void>)) ((<top> <textual-output-port>) => (<void>)))) ⇒ #t (is-a? display (lambda (<fixnum>) => (<fixnum>))) ⇒ #f (is-a? (unsafe-cast-signature (<procedure>) display) (lambda (<fixnum>) => (<fixnum>))) ⇒ #t ;;wrong!!!
the run–time predicate for all the type annotations describing closure objects is
procedure?
. What can I do?
It is possible to define aliases for type annotations:
(define-type <string-maybe> (or <false> <string>))
In the documentation file vicare-scheme there is a node ‘types’ which describes the typed language; it is WIP3 but enough up–to–date to be useful. Readers will notice that some type annotations’ syntaxes are similar (but not equal) to Typed Racket’s ones; this is inevitable: they chose good names.
Some built–in syntaxes (if
, and
, or
) propagate type
informations correctly:
(type-of (and 1 "ciao" 'blue)) ⇒ #[signature (<symbol>)] (type-of (and (read) 123)) ⇒ #[signature ((or <positive-fixnum> <false>))] (type-of (or (cast-signature ((or <false> <string>)) (read)) (cast-signature ((or <false> <fixnum>)) (read)))) ⇒ #[signature ((or <string> <false> <fixnum>))]
cond
is built upon if
:
(type-of (cond ((read) 123) ((read) "ciao") (else 'blue))) ⇒ #[signature ((or <positive-fixnum> <string> <symbol>))] (type-of (cond ((read) 123) ((read) => (lambda ({_ <string>} x) "ciao")) (else 'blue))) ⇒ #[signature ((or <positive-fixnum> <string> <symbol>))]
other syntaxes (case
) do not do it yet:
(type-of (case (read) ((a) 123) ((b) "ciao") (else 'blue))) ⇒ #[signature <list>]
a standalone <list>
identifier means: unspecified number of values, of
unspecified type. This is what I am working on these days, mostly. For correct type
propagation: non–core macros must be reimplemented as core macros.
There was once support for RHS type propagation. It means this:
(define O (new <vector> 1 2 3)) (type-of O) ⇒ #[signature (<vector>)]
it is not needed to explicitly specify the type annotation for the variable O
because the expander figures it out. At some point, I removed such feature because
it was problematic with the type infrastructure implemented back then.
It is now time to reconsider this feature. I will try something about it.
Work–in–progress. I went crazy the first time I saw this acronym in source code: what is this design pattern I never heard about?!?