core.typed question (maybe a bug?)

153 views
Skip to first unread message

Sven Richter

unread,
Apr 16, 2015, 3:39:28 PM4/16/15
to clo...@googlegroups.com
Hi,

I have this code:

(defalias html-label (t/HVec [Keyword (t/HMap :mandatory {:for String}) String]))
(defalias html-form (t/HVec [Keyword (t/HMap :mandatory {:id String}) t/Any *]))
(defalias html-form-group (t/HVec [html-label html-form]))
 
(t/ann dt->hiccup [(HVec [Keyword (U Keyword (HVec [Keyword Number])) t/Any t/Any *]) ->
                               html-form-group])
(defmulti dt->hiccup (t/fn [col :- pt/et-column]
                       (if (vector? (second col))
                         (first (second col))
                         (second col))))

And here comes the error message when checking this function:

Type Error (leiningen/td_to_hiccup.clj:25:34) Polymorphic function first could not be applied to arguments:
Polymorphic Variables:
        x
 
Domains:
        (t/HSequential [x t/Any *])
        (t/Option (t/EmptySeqable x))
        (t/NonEmptySeqable x)
        (t/Option (clojure.lang.Seqable x))
 
Arguments:
        (t/U Keyword (t/HVec [clojure.lang.Keyword java.lang.Number]))
 
Ranges:
        x :object {:path [(Nth 0)], :id 0}
        nil
        x
        (t/Option x)
 
in: (first (second col))
in: (first (second col))
 
 
ExceptionInfo Type Checker: Found 1 error  clojure.core/ex-info (core.clj:4403)

My assumption is that the check (if (vector? (second col will return only true if it is
this type: (HVec [Keyword Number]). However, I have the impression that core.typed does not resolve the if expression properly.
Or maybe I am missing something completely.

Any hints or recommendations?

Thanks,
Sven


Ambrose Bonnaire-Sergeant

unread,
Apr 16, 2015, 3:44:25 PM4/16/15
to clojure
I don't think second's type is is smart enough.

Try using nth or destructuring instead:

(let [[f s] v]
  (if (vector? s) (first s) s))

or

(if (vector? (nth v 1)) (first (nth v 1)) s)

Thanks,
Ambrose

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sven Richter

unread,
Apr 16, 2015, 4:43:41 PM4/16/15
to clo...@googlegroups.com, abonnair...@gmail.com
Hi,

I tried both destructuring and the nth form instead of second and first. None of which worked.

However, if I change the Union to Intersection in
(t/HVec [Keyword (t/U Keyword (t/HVec [Keyword Number])) t/Any t/Any *])

it works for the definition of the multimethod. Does that make sense? I thought Union was either one type or the other.

Thanks,
Sven

Ambrose Bonnaire-Sergeant

unread,
Apr 16, 2015, 5:08:30 PM4/16/15
to clojure
I don't see an intersection, what do you mean?

Thanks,
Ambrose

Ambrose Bonnaire-Sergeant

unread,
Apr 16, 2015, 5:14:28 PM4/16/15
to clojure
Oh, you changed it to (t/HVec [Keyword (t/I Keyword (t/HVec [Keyword Number])) t/Any t/Any *])?

Unions are like `or`, intersections like `and`. This might work for checking the definition, as function bodies are
checked with a set of assumptions about parameter types.

However it should be impossible to call this function as you cannot construct a type of (I Keyword (HVec ...)).

Thanks,
Ambrose

Sven Richter

unread,
Apr 16, 2015, 5:15:22 PM4/16/15
to clo...@googlegroups.com, abonnair...@gmail.com
I meant when I change:

(t/HVec [Keyword (t/U Keyword (t/HVec [Keyword Number])) t/Any t/Any *])  to  (t/HVec [Keyword (t/I Keyword (t/HVec [Keyword Number])) t/Any t/Any *])
                                ^^                                                                                         to                                  ^^
Still I think that making an intersection of it is wrong conceptually.


Thanks,
Sven

Ambrose Bonnaire-Sergeant

unread,
Apr 16, 2015, 5:25:42 PM4/16/15
to clojure
It might help thinking in terms of Java interfaces, Foo and Bar.

(definterface Foo
  (foo []))
(definterface Bar
  (bar []))

(I Foo Bar) is a value that extends both Foo and Bar.

(deftype IImp []
  Foo
  (foo [this])
  Bar
  (bar [this]))

(->IImp) is of type Foo, Bar, (I Foo Bar) and (U Foo Bar).

Assuming we assign (->IImp) the type (I Foo Bar), we can call these safely:

(let [i :- (I Foo Bar), (->IImp)]
 (.foo i)
 (.bar i))

A type that just implements Foo is not a Bar, so we can't claim it's a Foo *and* a Bar.

(deftype UImp []
  Foo
  (foo [this]))

(->UImp) is of type Foo, and (U Foo Bar).

Assuming we assign (->UImp) the type (U Foo Bar), the same operations now must cast at runtime.

(let [i :- (U Foo Bar), (->UImp)]
 (if (instance? Foo)
  (.foo i)
  (.bar i))


Thanks,
Ambrose

Sven Richter

unread,
Apr 16, 2015, 5:28:49 PM4/16/15
to clo...@googlegroups.com, abonnair...@gmail.com
Now thats a really nice explanation of union versus intersection in termes of types.

Thank you very much for that,
Sven

Sven Richter

unread,
Apr 17, 2015, 2:39:13 AM4/17/15
to clo...@googlegroups.com, abonnair...@gmail.com
I added your explanation the the wiki of core.typed: https://github.com/clojure/core.typed/wiki/Intersection-vs.-Union I hope that is fine for you.




Am Donnerstag, 16. April 2015 23:25:42 UTC+2 schrieb Ambrose Bonnaire-Sergeant:

Sven Richter

unread,
Apr 17, 2015, 3:03:49 AM4/17/15
to clo...@googlegroups.com, abonnair...@gmail.com
Hm,

Is it possible that core.typed may be influenced by the repl state? New day and a new try I got these both working:

(t/ann dt->hiccup [(t/HVec [Keyword (t/U Keyword (t/HVec [Keyword Number])) t/Any t/Any *]) -> html-form-group])
(defmulti dt->hiccup (t/fn [col :- (t/HVec [Keyword (t/U Keyword (t/HVec [Keyword Number])) t/Any t/Any *])]

(if (vector? (second col))
(first (second col))
(second col))))

and

(t/ann dt->hiccup [(t/HVec [Keyword (t/U Keyword (t/HVec [Keyword Number])) t/Any t/Any *]) -> html-form-group])
(defmulti dt->hiccup (t/fn [col :- (t/HVec [Keyword (t/U Keyword (t/HVec [Keyword Number])) t/Any t/Any *])]
(let [[_ s] col]
(if (vector? s) (first s) s))))

Which are the same basically regarding type declarations. Sorry for making such a noise,
maybe a simple repl restart would have fixed this.

Thanks,
Sven
Reply all
Reply to author
Forward
0 new messages