Fork me on GitHub
#clojure-spec
<
2018-06-14
>
borkdude11:06:06

what’s the way out here, alter-var-root? https://github.com/bhb/expound/issues/19

Alex Miller (Clojure team)12:06:25

set! will only work on a dynamic var if you are in the dynamic scope of a binding call

Alex Miller (Clojure team)12:06:54

Repls like clojure.main establish this

Alex Miller (Clojure team)12:06:47

So you either need to use binding or modify the root value with alter-var-root

borkdude12:06:21

clear. Is there also something like *print-length* but for strings?

Alex Miller (Clojure team)12:06:40

You could override the print-method for String, although that might have some adverse consequences

borkdude12:06:20

probably not a good idea 🙂 the reason I ask is that a spec error (with expound) flooded my emacs buffer so bad, I had to forcequit it…

bbrinck13:06:58

@borkdude although it elides potentially useful information, you can configure expound to not print out “failing spec” info, which would likely shorten the output considerably.

alex-dixon13:06:12

Is there an idiomatic way to check if a spec exists?

alex-dixon13:06:59

i.e. given a namespaced keyword how to check if a spec is registered for it

taylor13:06:58

you could (s/form ::spec) and it returns :clojure.spec.alpha/unknown nope use s/get-spec which returns nil for unknown specs

🎉 4
alex-dixon13:06:15

@taylor I’m getting a compiler exception for an unknown spec instead of a keyword

taylor13:06:52

can you paste the exception here?

taylor13:06:34

oh sorry, I think I tested this with a predicate function and not a keyword

taylor13:06:14

s/form does throw an exception if you give it a ::keyword that has no registered spec

alex-dixon14:06:12

Ok. Maybe I’ll just implement with try catch

taylor14:06:16

oh there's s/get-spec

taylor14:06:14

(def registered? (comp some? s/get-spec))

alex-dixon14:06:20

Perfect. Thanks lol

taylor14:06:34

I didn't know this existed either :man-shrugging: never had to look up a spec like that

alex-dixon14:06:31

(defn registered-spec? [x]
  (and (qualified-keyword? x)
       (some? (s/get-spec x))))
Yeah. Working on something where a macro may receive a namespaced keyword with an associated spec…so hopefully this all works out at compile time. Unfortunately have to do actual work now. Thanks a lot for your help…was going to hack something in but I feel way better with this

4
noisesmith20:06:55

given that macro expansion is a simplification step before making bytecode, you either end up with a much more complex compiler or taking the huge performance hit of having an interpreted language rather than a compiled one

noisesmith20:06:06

(in order to have first class macros)

johanatan20:06:52

@noisesmith i'm not arguing for first-class macros (although that would be nice). i'm arguing for not using second-class macros in libraries

johanatan20:06:58

and forcing their proliferation onto users.

noisesmith20:06:29

oh, I misinterpreted you then

johanatan20:06:28

[sorry, yea, it wasn't clear from without the context]

cjsauer20:06:27

Can I generate specs en masse? Something like:

(doseq [k my-keys]
  (s/def k (s/double-in :infinite? false :NaN? false :min 0)))

taylor20:06:58

it's registering the specs to the literal symbol k

cjsauer20:06:43

This was my gut feeling of what was going on. Any way to "force" it to evaluate the keyword? At this point I can see the value of writing them out by hand, but still curious...

cjsauer20:06:57

Smells like a macro...

donaldball20:06:52

I have done:

(doseq [[spec-kw field-spec desc] fields]
  (eval `(s/def ~spec-kw ~(build-internal-spec field-spec))))

donaldball20:06:58

I don’t even feel bad about it.

taylor20:06:59

yeah you could use a macro to spit out a bunch of s/def's for your keywords:

(defmacro alias-kws [ks]
  (let [defs (map #(list 's/def % ::my-spec) ks)]
    `(do ~@defs)))

cjsauer21:06:24

@donaldball interesting...using eval does do exactly what I'm after. It's a bit of a hack, but it beats having to repeat these massive lists of keywords over and over again...

donaldball21:06:30

It would be nicer if spec had an explicit affordance for this use case, but I don’t really think it’s abusive to take advantage of the fact that clojure is a lisp 😛 . I wouldn’t reach for this often, mind, but in my case I had a gigantor table of fields for a structured file and this lets me leverage an edn representation for spec validation as well as actually e.g. generating serializers

cjsauer21:06:19

Very cool, I agree that there are definitely valid use cases. Not to mention that the prospect of generating specifications from concretions is extremely interesting in its own right :thinking_face: Appreciate the help (@taylor as well, thank you)

cjsauer20:06:38

For some reason I'm getting "unable to resolve spec"...

johanatan20:06:55

@cjsauer most (all?) attempts to meta-program spec will fail-- it's apparently intended to be hand-written in the first-order only.

cjsauer20:06:20

Ooph...ok, thanks @johanatan

cjsauer20:06:25

generates all specs directly in emacs buffer and calls it a day

cjsauer20:06:32

I ❤️ Clojure

seancorfield20:06:02

@johanatan as noted, spec is currently built for human written code/input. There are plans for a more programmatic API which will open up meta-programming. I think building the latter first would have led to a lot more breaking changes (since folks would have built code against the API). Make sense?

parrot 4
cjsauer21:06:24

@donaldball interesting...using eval does do exactly what I'm after. It's a bit of a hack, but it beats having to repeat these massive lists of keywords over and over again...