Fork me on GitHub
#schema
<
2024-08-10
conao319:08:05

I found there is no schema.core/defmacro . Is there anyone else who wants it?

ambrosebs19:08:10

are schemas expressive enough for macros?

conao300:08:12

yes. Similar to s/defn. The argument checks are the same as it, and the return value checks express what the result of the execution will look like, not the result of the macro expansion. That would help when using macros.

ambrosebs02:08:20

> return value checks express what the result of the execution will look like, not the result of the macro expansion. are you describing s/defmacro or s/defn?

conao302:08:58

s/defmacro ; I assume that

ambrosebs02:08:07

that's cool. I've tried similar things but I want to hear more about your ideas. Do you have an example macro that returns anything other than Any?

conao302:08:41

(defmacro adding-all [& args]
  `(+ ~@(map inc args)))
;;=> #'argparse.core/adding-all

(macroexpand
 '(adding-all 1 2 3))
;;=> (clojure.core/+ 2 3 4)
This is an illustrative example, but suppose we define such a macro. And this macro could be typed thus.
(s/defmacro adding-all :- s/Int
  [& args :- [s/Int]]
  `(+ ~@(map inc args)))

ambrosebs02:08:21

How would the result be checked?

conao302:08:05

That's right. I can't check, but I was assuming I would use it in a static analysis. If this macro is used where s/Str is expected it will be able to produce errors.

ambrosebs02:08:42

would the arguments be unchecked too?

conao302:08:55

no, I can check,, I see, macro just get symbol instead of its value.

ambrosebs02:08:54

Oh I see. I don't think many macros are this statically known.

ambrosebs02:08:39

most take expressions as arguments too, which would be Any.

conao302:08:15

Hmm. Might be a little difficult. I'll give it some more thought.

ambrosebs02:08:50

when I tried this I ended up with typing rules. for example for if:

;; Env |- e1 : T1
;; Env |- e2 : T2
;; Env |- e3 : T3
;; --------------------------------
;; Env |- (if e1 e2 e3) : (U T2 T3)
and let
;; Env       |- e1 : T1
;; Env, x:T2 |- e2 : T2
;; --------------------------------
;; Env |- (let [x e1] e2) : T2

ambrosebs02:08:14

are you aware of how spec treats macros?

conao302:08:21

I see. maybe we should have generic type before this?

ambrosebs02:08:07

yes exactly

👍 66
ambrosebs02:08:17

here's my experiment for if that returns the then branch (spec)

(s/def ::logical-true (s/and s/any? boolean))
(s/def ::logical-false #{false nil})

;; Env |- e1 : logical-true
;; Env |- e2 : T2
;; --------------------------------
;; Env |- (if e1 e2 e3) : T2
(s/def ::if-true-simple
  (t/all :binder (t/binder
                   :e1 (t/bind-tv :kind (t/prog-spec
                                          :type ::logical-true))
                   :t2 (t/bind-tv :kind t/any-spec)
                   :e2 (t/bind-tv :kind (t/prog-spec
                                          :type (t/tv :t2)))
                   :e3 (t/bind-tv :kind (t/prog-spec)))
         :body
         (t/macro-spec
           :args (s/cat :test (t/tv :e1)
                        :then (t/tv :e2)
                        :else (s/? (t/tv :e3)))
           :prog (t/prog-spec
                   :type (t/tv :t2)))))

conao302:08:53

Thanks, for clarification. What is the t here?

ambrosebs02:08:27

t is a type (or a schema). but there's a lot going on here, any particular part you'd like to know more about?

ambrosebs02:08:12

I reused the names from the typing rule in the spec, that might help. I can also just explain the whole thing if you'd like.

conao302:08:14

Sounds good. I'm still a newbie to Clojure, though, so I'll get used to it first. And I'll come back here again next time.

👍 66