Reputation: 119
I've started playing with the seemingly quite impressive clojure.typed library, but very shortly after I run into problems, even when trying to apply it to simple functions. Does anyone have experience with the library?
Problem 1
(typed/ann square [Double -> Double])
(defn square "Square of"
[num]
(* num num))
Type Error (clojure_study/ideas/swarm/vector_algebra.clj:15:3) Return type of static method clojure.lang.Numbers/multiply is java.lang.Long, expected java.lang.Double.
Problem 2
(typed/defalias CartesianVector '{:x Double :y Double})
(typed/ann v+ [CartesianVector * -> CartesianVector])
(defn v+ "Sum vector of vectors"
[& vectors]
(apply merge-with + vectors))
Type Error (clojure_study/ideas/swarm/vector_algebra.clj:28:3) Bad arguments to polymorphic function in apply in: (apply merge-with + vectors)
Problem 3
(typed/ann v- [CartesianVector CartesianVector -> CartesianVector])
(defn v- "Diff vector of vectors"
[v1 v2]
(merge-with - v1 v2))
Type Error (clojure_study/ideas/swarm/vector_algebra.clj:33:3) Polymorphic function merge-with could not be applied to arguments: Polymorphic Variables: k v
Thanks for any help offered.
Upvotes: 11
Views: 499
Reputation: 2549
Your answer is now 3 years old, so this may not be much help, but I was using Typed Clojure in a big production codebase around the same time and have some experience with it. Also, the answers that weavejester provided in your Reddit thread on the topic are pretty much spot-on, so I'm just going to re-summarize them here to save future visitors the inconvenience of having to click another link.
In general your approach is correct at a high level but you're running into areas in which core.typed
simply didn't (and maybe still doesn't) know how to behave smartly.
Here's what's going on:
Problem 1
This should probably be considered a bug on the behalf of core.typed
, because there is a function signature supporting Double
as a return type. You can circumvent this by using clojure.lang.Number
or clojure.core.typed/Num
instead, both of which encompass both Long
and Double
.
Problem 2
This is just a syntax error - that's not how you specify maps to core.typed
. You should be using an HMap
instead:
(t/defalias CartesianVector
(t/HMap :mandatory {:x t/Num, :y t/Num} :complete? true))
Problem 3
Unfortunately core.typed
cannot successfully infer that merge-with
(a core function) when applied to two maps of the same type will return a map of the same type. This is a limit of the type-checker. You can get around this by re-writing your function to explicitly merge rather than relying on merge-with
:
(defn v-
[{x1 :x, y1 :y} {x2 :x, y2 :y}]
{:x (- x1 x2), :y (- y1 y2)})
Upvotes: 1