Fork me on GitHub
#core-typed
<
2024-04-18
>
Prashant09:04:00

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

Prashant16:04:10

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

ambrosebs16:04:43

Yeah please put those examples. There's a scoping issue somewhere.

👍 1
ambrosebs16:04:35

You could try this: (ann-datatype [[x :variance :covariant]] SomeData [count :- (t/I x t/Num)])

👍 1
Prashant16:04:08

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?

Prashant16:04:51

I was also wondering if there's a cooler way to create a Result type using t/Match 😄

ambrosebs16:04:59

That looks like a type simplification issue. Maybe make Error's type param covariant?

ambrosebs16:04:59

IResult's param looks invariant to me.

ambrosebs16:04:34

But I struggle to combine object orientation with variance. Why is it contravariant?

ambrosebs16:04:15

Or rather, it's a subtyping issue. (Err (U a b)) is unrelated to (Err a) if Err is invariant.

Prashant16:04:28

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.

ambrosebs16:04:43

Invariant is the default.

ambrosebs16:04:03

Oh wait, I forgot I implemented variance inference.

ambrosebs16:04:44

But I guess it inferred invariant here?

Prashant16:04:32

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

Prashant16:04:39

I wonder if I can implement something simpler for Result type using t/Match ? something akin Rust's enum may be

ambrosebs16:04:51

Not sure. How would you implement this in vanilla clojure with just tagged maps? Might be an easier starting point for me to help.

👍 1
ambrosebs16:04:04

Or even with deftypes?

ambrosebs16:04:07

I guess that's what you sent me.

Prashant16:04:38

Yeah, I am still struggling with the type simplification on the Ok deftype

ambrosebs16:04:57

Did you mark it covariant?

Prashant16:04:03

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

ambrosebs17:04:28

bit of a mind bender 🙂

ambrosebs17:04:44

maybe you need to manually instantiate f

Prashant17:04:27

Dumb question. How would I do that?

ambrosebs17:04:30

((t/inst f v v) value) something like that, but intelligently chosen types

👍 1
ambrosebs17:04:53

it will at least give you a precise error message

Prashant17:04:10

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)]))) 

Prashant17:04:19

This is something I thought just now, so may not work.

Prashant17:04:11

I think I will take a break now. Spend some time with my toddler and unwind 🙂

❤️ 1
ambrosebs18:04:58

yeah this is heady stuff, also not that well supported. but I'm glad you're doing it.

❤️ 2