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.

Reply via email to