This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-04-18
Channels
- # babashka (12)
- # beginners (35)
- # biff (6)
- # calva (23)
- # cider (7)
- # clj-kondo (10)
- # cljs-dev (15)
- # clojure (81)
- # clojure-dev (2)
- # clojure-europe (13)
- # clojure-germany (1)
- # clojure-korea (2)
- # clojure-nl (1)
- # clojure-norway (19)
- # clojure-uk (7)
- # clojurescript (23)
- # core-typed (33)
- # cursive (7)
- # data-science (7)
- # datalevin (9)
- # hyperfiddle (1)
- # introduce-yourself (2)
- # malli (1)
- # matrix (17)
- # missionary (24)
- # music (1)
- # off-topic (15)
- # polylith (6)
- # reagent (10)
- # releases (5)
- # remote-jobs (1)
- # shadow-cljs (3)
- # squint (7)
- # xtdb (11)
- # yamlscript (6)
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 error
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 error
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?
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.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.
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 error
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)])))