Hi Alex, thanks for replying. Indeed I don't have practical use for s/form right now; I'm just trying to guess what could be a good use in the future :)
On Thursday, May 18, 2017 at 10:01:25 PM UTC+2, Alex Miller wrote: > > > > On Thursday, May 18, 2017 at 12:37:26 PM UTC-5, Leon Grapenthin wrote: >> >> I also have this problem. >> >> 1. If I create a dynamic spec constructor per defmacro and invoke it, >> it's s/form gives the primitive specs form - because spec doesn't provide >> me with a way to facilitate specs that capture their form. >> > > The idea of providing custom form serialization support is one I have > spent quite a bit of time looking at (in particular wrt s/&, s/keys*, and > the range specs, but in practice the same problem is being worked around in > the coll specs, etc). I've done spikes on three possible directions for > this and I can't say any of them is an unambiguous win so it's going to > require some Rich time at some point to make further decisions. In some > ways it's an analogous problem to how custom gens are implemented. > > >> 2. If I apply that invocation to another primitive spec, s/form of that >> just contains the macro invocation form. >> >> If this is intentional, I'd also like to know the underlying design rule >> (not the reasons why that is so in the current implementation): Why should >> this result in two different forms for one and the same spec to deal with, >> instead of one. >> > > The principle is to capture the spec form at the time of construction for > the purposes of a) reporting and b) serialization via s/form. That seems > satisfied in both cases. > > >> The reason to create "dynamic" spec constructors is usually to avoid >> boilerplate when writing specs. Unless I'm missing what I shouldn't do, I'd >> prefer to have direct support for that spares me having to deal with two >> forms. >> > > In what way are you "dealing with" two forms? Why is that a problem? > > >> >> Kind regards, >> Leon. >> >> On Thursday, May 18, 2017 at 6:35:46 PM UTC+2, Alex Miller wrote: >>> >>> >>> >>> On Wednesday, May 17, 2017 at 3:02:17 PM UTC-5, marian...@vacuumlabs.com >>> wrote: >>>> >>>> Hi, >>>> >>>> I am writing a function that transforms Specs to another formats >>>> (similar to the JSON Schema). Assuming from this post >>>> <http://www.metosin.fi/blog/clojure-spec-as-a-runtime-transformation-engine/>, >>>> >>>> I am not the only one. There is no surprise that I am using >>>> clojure.spec/form. Unfortunately I am not fully satisfied with its >>>> output. To illustrate the problem let's suppose that my transformer will >>>> be >>>> used by a third person who like to write its own spec-generating helpers: >>>> >>>> (require '[clojure.spec.alpha :as spec]) >>>> >>>> (spec/def ::forgivable-keyword (spec/conformer (fn [x] (cond (keyword? >>>> x) x >>>> (string? >>>> x) (keyword x) >>>> true >>>> ::spec/invalid)))) >>>> >>>> (defn kw-enum [& enum-values] (spec/and ::forgivable-keyword (apply >>>> hash-set enum-values))) >>>> >>>> >>> s/and (and all of the spec forms) are macros to facilitate capturing the >>> spec form for use in s/form and error reporting. >>> >>> In this case, (apply hash-set enum-values) is not either a predicate or >>> a set and thus is not a valid spec to use in s/and. >>> >>> I presume what you're looking for is the ability to dynamically create >>> specs - for this, please consider using either eval or a macro. >>> >>> >>> >>>> Cool! Let's look how can my transformer cope with it! >>>> >>>> (spec/form (kw-enum :a :b :c)) >>>> ; (clojure.spec.alpha/and >>>> :my-ns/forgivable-keyword (clojure.core/apply clojure.core/hash-set >>>> enum-values)) >>>> >>>> Ouch! Have I just seen a local symbol in the form? I am sorry third >>>> person, I won't be able to transform the output of your spec-generating >>>> functions. Unless they are macros: >>>> >>>> (defmacro >>>> kw-enum [& enum-values] `(spec/and ::forgivable-keyword ~(apply >>>> hash-set enum-values))) >>>> >>>> (spec/form (kw-enum :a :b :c)) >>>> ; (clojure.spec.alpha/and :my-ns/forgivable-keyword #{:c :b :a}) >>>> >>>> This approach looks better. How does it work in combination with other >>>> specs? >>>> >>>> (spec/form (spec/nilable (kw-enum :a :b :c))) >>>> ; (clojure.spec.alpha/nilable (my-ns/kw-enum :a :b :c)) >>>> >>>> There we are. A third-person's function is in the form. We could use >>>> eval to resolve it, but do we want to? >>>> >>> >>> Sure. It resolved to a spec last time, why not this time? OR, why do you >>> need to resolve it at all? (this to some degree depends on the use case) >>> >>> >>>> It has been already evaluated once. What if there are some side effects? >>>> >>> >>> Then I'd say you already have more important problems. >>> >>> >>>> Practically, one has no option to write spec-generating function and >>>> maintain usability of the spec/form at the same time. Therefore one of >>>> four situations must have happened. Either I got something wrong, Specs >>>> are >>>> not meant to be introspected, Specs are not meant to be generated or >>>> spec/form is badly designed. Which one is it? >>>> >>> >>> Seems to me like you can generate and introspect this fine. I think that >>> if you are introspecting spec forms, you will encounter resolved symbols >>> referring to functions. How you approach the use of those depends on your >>> context. >>> >>> Another option still coming (work in progress) is to use specs on spec >>> forms (CLJ-2112) to create conformed spec data, then s/unform back to a >>> spec form. >>> >>> >>>> >>>> (In the case of the fourth one I have some suggestions, but lets keep >>>> them for later conversation) >>>> >>>> Thanks for your time >>>> >>>> Marian >>>> >>> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.