Máté Magyari
Máté Magyari

Reputation: 119

Clojure.typed basics

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

Answers (1)

Venantius
Venantius

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

Related Questions