http://www.cs.colorado.edu/~siek/pubs/pubs/2006/siek06:_grad...
124 karma · joined July 18, 2011
http://www.cs.colorado.edu/~siek/pubs/pubs/2006/siek06:_grad...
Say you had some untyped function `f` that is Dyn -> Dyn.
(defn f [a :- Dyn] :- Dyn a)
Running
(inc (f 1))
would wrap 1 in Dyn, then a Dyn exits as a return value, so no further wrapping is needed. Now it's `inc`'s responsibility to ensure it's really being passed a number, so it unwraps the Dyn and finds an int inside.
So you're right - it only works with first-order values without this kind of machinery, which end up looking pretty much like what I talk about in the article.
`Any` is also often called `Dyn` or `Dynamic` in normal typed languages, which is slightly different to `Any` here (core.typed's `Any` is the supertype to all types, `Dyn` is usually both the super and subtype to all types).
Typed Clojure and Typed Racket are very closely related in theory and implementation.
We can express lengths of sequences for example, but they only support explicit lengths: you can't put a type variable in the length position.
I also commented on the blog post explaining the terms I used.
Both sides of b ... b are actually completely different. The left is a type (called a "pre-type") and the right is a dotted type variable currently in scope.
The trick is that the dotted type-variable is also scoped as a normal free variable in the pre-type.
It might help thinking of "b ... b" as expanding to "b1 b2 b3 b4 b5", where each is a fresh type variable.
Then, consider "(NonEmptySeqable b) ... b" as expanding to "(NonEmptySeqable b1) (NonEmptySeqable b2) (NonEmptySeqable b3) (NonEmptySeqable b4) (NonEmptySeqable b5)".
The b's "match up" pairwise, but they're quite different than what you might expect.
Almost all the design/implementation work was done via Typed Racket anyway. I stole a lot of it and spent most of the time on Clojure-specific problems.
I'm probably responsible for the thinking that annotations are only needed for "top levels and function parameters". I usually forget about the other ones, but I think those two are the most significant.
(ann my-keys (All [a] [(t/Map a Any) -> (t/Coll a)])
This rough screencast describes on aspect to the approach http://vimeo.com/55280915
I guess Typed Clojure is more powerful than Typescript in a few ways, but it's more about how well the type system fits the language. I've never used Typescript, but it seems to fit nicely, with interesting tradeoffs.
Concretely, I've extended several minor ideas.
Typed Clojure uses occurrence typing in sequential forms, as well as conditionals: http://frenchy64.github.io/2013/09/08/simple-reasoning-asser...
We can type check (filter identity coll) a little more accurately (which is actually quite hard to do): https://github.com/clojure/core.typed/blob/master/src/main/c...
The type system's interaction with Java's type system is interesting, which is something I've fleshed out.
I have heterogeneous maps as well as heterogeneous vectors, and support complex operations like merge. Unsure if relevant to Racket.
There are lots of other ideas which I need to implement to type check Clojure, but aren't necessarily crucial to type checking Racket, but would be nice to have.