I am stuck at trying to set bounds using ann-datatype . I think I am missing something really basic.
Some help would be greatly appreciated.
(ann-datatype [[x :variance :covariant :< t/Num]] SomeData [count :- x])
(deftype SomeData [count])
;; =>
Type Error (NO_SOURCE_FILE)
Type Error (:<NO LINE>) Type function argument number 1 (x) has kind (t/Type :< t/Num) but given x with missing bounds
in: ((t/TFn [[x :variance :covariant :< t/Num]] (SomeData x)) x)
Execution error (ExceptionInfo) at clojure.core.typed.errors/print-errors! (errors.cljc:299).
Type Checker: Found 1 errorIt's a bug.
Oh! Should I log an issue at Github?
I tried to get this to work using t/Match but it didn't work either
e.g.
(defalias NumOrError (t/TFn [[y :variance :invariant]]
(t/Match y
t/Num :-> t/Num
(t/Not t/Num) :-> t/TCError)))
(t/ann-datatype [x] SomeData [count :- (NumOrError x)])
(deftype SomeData [count])
(SomeData. 10)
and (t/check-ns-clj) reported errors:
Polymorphic function (new SomeData 10) could not be applied to arguments:
Polymorphic Variables:
x
Domains:
(fp.typed.monads/NumOrError x)
Arguments:
(t/Val 10)
Ranges:
(SomeData x)
in:
(new SomeData 10)
Execution error (ExceptionInfo) at clojure.core.typed.errors/print-errors! (errors.cljc:299).
Type Checker: Found 1 errorYeah please put those examples. There's a scoping issue somewhere.
You could try this: (ann-datatype [[x :variance :covariant]] SomeData [count :- (t/I x t/Num)])
I was trying to create a simple Result type akin to Rust but couldn't get it to work.
(t/ann-protocol [[M :variance :contravariant]]
IResult
then (t/All
[a b]
[(M a) [a :-> (t/U a b)] :-> (M (t/U a b))]))
(defprotocol IResult
(then [this f]))
(t/ann-datatype [e] Err [err :- e] :extends [(IResult Err)])
(deftype Err [err]
IResult
(then [this _]
this))
(ann-datatype [v] Ok [value :- v] :extends [(IResult Ok)])
(deftype Ok [value]
IResult
(then [_ f]
(try
(let [res (f value)]
(cond
(satisfies? IResult res) res
(instance? Exception res) (Err. res)
:else (Ok. res)))
(catch Exception e
(Err. e)))))
(t/chec-ns-clj) would always report following errors:
Type Error
Type mismatch:
Expected: (Err (t/U b a))
Actual: (t/I (Err e) (Err a))
in:
`this`
Execution error (ExceptionInfo) at clojure.core.typed.errors/print-errors! (errors.cljc:299).
Type Checker: Found 1 error
Could this also be related to the same issue?I was also wondering if there's a cooler way to create a Result type using t/Match 😄
That looks like a type simplification issue. Maybe make Error's type param covariant?
IResult's param looks invariant to me.
But I struggle to combine object orientation with variance. Why is it contravariant?
Or rather, it's a subtyping issue. (Err (U a b)) is unrelated to (Err a) if Err is invariant.
Thanks! for the tip
(ann-datatype [[e :variance :covariant]] Err [err :- e] :extends [(IResult Err)])
caused the Err type mismatch to pass.
I was under the impression just specifying type variable e.g. [e] has implied :variance of :covariant
I made IResult's param's type variable contravariant as then can take can be like [(Ok a) -> (Err b)].
Maybe it's wrong. I will try with invariant.Invariant is the default.
Oh wait, I forgot I implemented variance inference.
But I guess it inferred invariant here?
I do remember one of the type check messages yelling at me for setting wrong variance. I can't recall whether it was for a ann-protocol, a TFn or a ann-datatype
I wonder if I can implement something simpler for Result type using t/Match ?
something akin Rust's enum may be
Not sure. How would you implement this in vanilla clojure with just tagged maps? Might be an easier starting point for me to help.
Or even with deftypes?
I guess that's what you sent me.
Yeah, I am still struggling with the type simplification on the Ok deftype
Did you mark it covariant?
Yes, I also simplified code quite a bit
(t/ann-protocol [[M :variance :invariant]]
IResult
then (t/All
[a b]
[(M a) [a :-> (t/U a b)] :-> (M (t/U a b))]))
(defprotocol IResult
(then [this f]))
(ann-datatype [[e :variance :covariant]] Err [err :- e] :extends [(IResult Err)])
(deftype Err [err]
IResult
(then [this _]
this))
(ann-datatype [[v :variance :covariant]] Ok [value :- v] :extends [(IResult Ok)])
(deftype Ok [value]
IResult
(then [_ f]
(Ok. (f value))
;; Ideally this execution will be wrapped in try-catch block
))
Now the error is on
Function f could not be applied to arguments:
Domains:
a
Arguments:
v
Ranges:
(t/U a b)
in:
(f value)
Execution error (ExceptionInfo) at clojure.core.typed.errors/print-errors! (errors.cljc:299).
Type Checker: Found 1 errorbit of a mind bender 🙂
maybe you need to manually instantiate f
Dumb question. How would I do that?
((t/inst f v v) value) something like that, but intelligently chosen types
it will at least give you a precise error message
Just to contrast current deftype and protocol approach with t/Match
(defalias Ok (t/TFn [[x :< (t/Not Exception)]] x))
(defalias Err (t/TFn [[x :< Exception]] x))
(defalias Result (t/TFn [[x]]
(t/Match x
Exception :-> (Err x)
(t/Not Exception) :-> (Ok x))))
(ann then (t/All [x]
(t/IFn [(Err x) [x :-> x] :-> (Err x)]
[(Ok x) [x :-> x] :-> (Result x)])))
This is something I thought just now, so may not work.
I think I will take a break now. Spend some time with my toddler and unwind 🙂
yeah this is heady stuff, also not that well supported. but I'm glad you're doing it.
fixed the original bug https://github.com/typedclojure/typedclojure/commit/fb9e5073270d958c4be1a6e0011b61297a1bb01f