Gradual typing for Clojure
frenchy64.github.io
frenchy64.github.io
In my blog post "How ignorant am I, and how do I formally specify that in my code?" I tried to communicate why I think this is important. I am not sure I found the correct words, but the idea is that when I start on a problem, especially a problem I've never dealt with before, I don't want to specify a contract because I consider myself too ignorant to specify a contract. The flip side of that is when you see a contract in my code, you know that you are looking at a bit of code where I feel I have overcome ignorance and learned enough to specify something strict.
"http://www.smashcompany.com/technology/how-ignorant-am-i-and...
That said, I find my experience differs around the following:
"[W]hen I start on a problem, especially a problem I've never dealt with before, I don't want to specify a contract because I consider myself too ignorant to specify a contract."
I find that's precisely when I find types the most valuable. I can start to sketch out the properties that I think should hold, and the type checker helps me think ahead and catch inconsistencies before I've coded all the way to them.
It also helps me write not-quite-right code at the outset with confidence, knowing that as I discover that I'm wrong about things I will have assistance in finding where I am wrong about things, and hopefully more quickly get to sufficiently right and sufficiently complete code.
I recognize that much of this is subjective, may well not apply to everyone, and might even be wrong (it's a hard thing to measure)... but I thought I'd share my POV.
The interesting technology thus is the "injection" `t -> Any` which is universally valid but appears to have its own contract attached as well which attempts to prevent a consume of such an `Any` from using the type `t` incorrectly.
`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).
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.