On Tuesday, October 11, 2016 at 1:30:18 PM UTC-5, plamen.use...@gmail.com 
wrote:
>
> Hello,
>
> I have a problem which is probably not in the spirit of clojure.spec as 
> being a library for "only" checking/generating valid values, but of 
> substantial practical value for my use case:
>
> Let say I have a function for checking if a double precision number is 
> parsable from a string (where possible performance penalties because of 
> communicating non-parsable strings through try/catch in the implementation 
> is not part of my question):
>
>
> (defn str-parsable-double? [s]
>   "Note the IMPLIED transformation from string to a double"
>   (try
>     (Double/valueOf s)
>     (catch NumberFormatException e
>       false)))
>
>
>
It's not detrimental here (other than this fn won't have the intended 
docstring), but this code has the docstring in the wrong place - it goes 
before the arglist, not after. 
 

> and have a spec using this function:
>
> (s/def ::str->double str-parsable-double?)
>
>
> We could actually chain checks for a single value as in:
>
> (s/def ::str->double (s/and string? str-parsable-double?))
>
>
This is a good practice. In general most specs will not generate 
automatically unless you start from a type-based predicate so this 
particular part I think is very much in line with good practices.
 

> and we could check for the conformity of a value as per:
>
> (s/conform ::str->double "3.14")
> => "3.14"
> and 
> (s/conform ::str->double "Pizza")
> => :clojure.spec/invalid
>
> Until now everything is ok, now my the questions:
>
> In my real world example I need a chain of a combination of checks and 
> transformations in the following way:
> ::check1 ::check2 ::check-and-transform3 ::check-4-on-transformed-value 
> ::check-5-on-transformed value
> or something like
> (s/def ::transforming-check (s/and string? ::str->double ::bigger-than-zero? 
> ::smaller-than-pi ... etc ...))
>
> As the result of 
> (s/conform ::str->double "3.14") is the input value as a string instead of 
> the result, 
>
>
I would need implement ::bigger-than-zero? and the rest of the checks as 
operating on strings, which would mean that I need in each check to transform 
the string into a double, which in my case is for performance reasons bad.
>
> On the other side I would be able to do the checks in a 2 step fashion, which 
> goes against my understanding of the aim of clojure.check to be able to 
> create through composition a single set of validations for a single value.
> This also doesn't solve fully the problem with the multiple parsing of the 
> first data type before the transformation: a parsing happens in the 
> ::str->double step as well in the then explicit transformation step before 
> the final checks based then on the actual double.
>
>
You can use s/conformer for this, although I will share the caution that 
use of s/conformer in your registered specs means that you are obscuring 
(and throwing away info) from the input value for your spec consumers. This 
is not inherently bad, but it is a tradeoff that should be considered when 
mixing validation and conversion. You could keep the conversion out of the 
spec and do that via a transformation or via a non-registered spec too. I 
can't say which of these is "right" for you, but you should at least think 
through these things ahead of time. A generally good practice is to also 
supply an unformer function with your conformer (here, probably just str 
would work) - this would allow you to run the spec backwards with s/unform 
and retrieve the original value.



> So - is there a way to compose checks in a single one, where some of them 
> change the underlying type of the value for subsequent validations (I may 
> miss something in the Clojure documentation, and pointers to it would be very 
> welcome)?
>
> If not - why s/conform returns the input value instead of the result value? 
> As being on the caller site of s/conform I know what I passed and I know what 
> s/conform would give me in the negative outcome of the validation.
> If s/conform while iterating/recursing through the actual spec would apply 
> the checks on returned values of previous checks instead always on the input 
> - the problem would be solved, without negatives for the calling sites (as 
> because of the previous sentence).
> This could be solved for example (not sure if I see every detail yet, but at 
> least as a pointer) in that in the clojure.spec code
>
> Spec
> (conform* [_ x] (let [ret (pred x)]
>                   (if cpred?
>                     ret
>                     (if ret x ::invalid))))
> the value of cpred? could be passed from the calling site (or if don't miss 
> something be even per default true).
>
> In any case, I would be thankfull for any suggestions solving both proplems: 
> how to express such checks in a good way and how to avoid reparsing values 
> again and again (where the current example is for just strings to doubles, 
> but the actual problem could involve any transformations on the value incl. 
> type).
>
> With best regards
> Plamen
>
>
>
>
>
>

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