What does this clojure.core.typed type error mean?

clojure, clojure-core.typed, types

Solution

The first part of the error tells you this concerns a call to `clojure.core/keys`. You can lookup the type with `(cf keys)`.

` (All [k] [(Map k Any) -> (Seq k) :object {:id 0 :path [Keys]}]) `

The error is basically summarising this polymorphic type juxtaposed with the actual types provided to the function.

The `Polymorphic Variables` list all the variables in the `All` binder and their type bounds. `k` is the only variable, which has essentially no bounds, so `k` is displayed.

The `Domains` list all the parameter types (to the left of the `->`) in order. If multiple arities were specified with `Fn`, each parameter list would be displayed sequentially.

The `Arguments` show you what types are actually passed to the function. The code at 14:23 is presumably this call `(keys hm)`, so the type of the first argument is displayed: `(t/Option (t/Map k v1))`

The `Ranges` list all the return types (to the right of the `->`) in order.

Sometimes there is an `Expected` type, which must match up with a `Range` in the same way all the `Arguments` must match up with a `Domain`.

We can diagnose this error by comparing the `Domains` with the `Arguments`. The list of `Arguments` must fit under one list of `Domains`, and the match is attempted top-down. If no `Domains` fit with the `Arguments`, we get a type error like this; it's often too complicated to pinpoint exactly where the constraint algorithm failed, so the user is presented with a lot of information.

In this case, we try and fit the argument `(t/Option (t/Map k v1))` under the domain `(t/Map k Any)`, which fails. This is because the argument `(t/Option (t/Map k v1))` is the same as `(U nil (t/Map k v1))`, and `nil` does not fit under the domain `(t/Map k Any)`.

There are a couple of ways to fix this. You basically need to ensure `keys` isn't passed `nil`. Here's one option:

` (keys (or hm {})) `

Problem

I want to get the `clojure.core.typed` type check passing, but I'm getting a type error that I don't understand. My questions are: - What does the error below mean? - How can I fix it? Here is my code (which I realize is incorrect): ``` (ns clj.util.map (:require [clojure.core.typed :as t])) (t/ann map-vals (All [k v1 v2] (Fn [ (Fn [(t/Option v1) -> (t/Option v2)]) (t/Option (t/Map k v1)) -> (t/Option (t/Map k v2)) ]))) (defn map-vals ;; FIXME: Incorrect code "Apply a function to each of the values in a map, returning the updated map." [f hm] (t/doseq> [k :- Any (keys hm)] (assoc hm k (f (get hm k))))) ``` Here is the output of `lein typed check clj.util.map`: ``` Initializing core.typed ... "Elapsed time: 6697.604 msecs" core.typed initialized. Start collecting clj.util.map Finished collecting clj.util.map Collected 1 namespaces in 6851.111 msecs Start checking clj.util.map Checked clj.util.map in 968.041 msecs Checked 1 namespaces (approx. 21 lines) in 7823.552 msecs Type Error (clj.util.map:14:23) Polymorphic function clojure.core/keys could not be applied to arguments: Polymorphic Variables: k Domains: (t/Map k Any) Arguments: (t/Option (t/Map k v1)) Ranges: (t/Seq k) :object {:path [Keys], :id 0} in: (clojure.core/keys hm) in: (clojure.core/seq (clojure.core/keys hm)) Type Checker: Found 1 error Found errors Subprocess failed ```

Original source