This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-04-17
Channels
- # aws (10)
- # beginners (64)
- # boot (3)
- # cider (20)
- # cljs-dev (32)
- # cljsrn (6)
- # clojure (126)
- # clojure-dusseldorf (3)
- # clojure-finland (1)
- # clojure-greece (1)
- # clojure-italy (7)
- # clojure-poland (3)
- # clojure-spec (46)
- # clojure-uk (100)
- # clojurescript (37)
- # cursive (11)
- # datomic (6)
- # defnpodcast (2)
- # emacs (1)
- # events (3)
- # figwheel (2)
- # fulcro (20)
- # immutant (2)
- # jobs (1)
- # jobs-discuss (9)
- # keechma (3)
- # lein-figwheel (1)
- # luminus (2)
- # lumo (3)
- # mount (2)
- # off-topic (19)
- # om (3)
- # om-next (2)
- # onyx (20)
- # other-languages (55)
- # parinfer (11)
- # pedestal (8)
- # portkey (3)
- # protorepl (3)
- # re-frame (22)
- # ring (9)
- # rum (1)
- # shadow-cljs (82)
- # spacemacs (28)
- # sql (15)
- # test-check (15)
- # testing (2)
- # tools-deps (102)
- # vim (26)
I have a few transforms that are related in my application.
{:aH "abc"} ;;phase-1
{:aH :what-x-means} ;;phase-2
{:a-h :what-x-needs-to-be-for-an-external-app} ;;phase-3
What would be cool is if I could somehow link all of these specs together, and control generation. So, an initial spec for phase 1 would refer to phase 2, and phase 2's spec would refer to phase 3.where a named conformer would be the transform between two phases, so I could (s/def ::phase-1->phase-2 (s/conformer ...))
(s/conform ::phase-1->phase-2 {:aH "abc"})
@d._.b Hm, hard to say without seeing the code, but I suspect it’d be easier to just write transform functions with a transformation library and use the specs to validate each transform is working
Generally speaking, using a conformer to transform data can cause issues https://groups.google.com/d/msg/clojure/Tdb3ksDeVnU/LAdniiZNAgAJ
@bbrinck yes, this makes sense to me. it is fine for me to write the transform functions and validate the transform, but for some of these specs, the difference is very small. For instance, "person": {:name "bob"} => {:name (get {"bob" :fun-bob} "bob")} => {:nick-name "fun-bob"}. It would be nice if I could link the specs as an ordering, and then choose which phase I want to generate.
@d._.b Yep, I can see how this would be convenient. I can’t speak for spec maintainers, but from what I’ve read so far, they have consistently indicated they want to stay away from transformation (and leave this to other libraries - both libraries that are spec-aware or those that are spec-agnostic)
I can certainly see the use, but this can’t be done in spec today and I doubt it will be added 🙂 . https://github.com/nathanmarz/specter might be a good fit here
Not sure if it is something targeted at what you are hoping to do, but late in the Google group discussion linked above is a mention of the project spec-coerce, which the author says "instead of making conforms that do coercion, it uses the spec and a separated registry to conform the value (similar to what spec does to find the generators for a given spec)". https://github.com/wilkerlucio/spec-coerce
+1 spec-coerce
@d._.b tested spec-driven data expansion some time ago, via conforming. Not sure if that’s an good idea, but here’s an example: https://www.metosin.fi/blog/clojure-spec-as-a-runtime-transformation-engine/#data-macros
it’s not a good idea
would it be a good idea to add support for spec coercion in the core? or support for generic walking with coercion as one application for walking.
Generic walking yes, coercion maybe
I renamed CLJ-2251 to “Generic Spec Walking for clojure.spec”. Is something like that coming? Would you be interested in a demo / patch of that?
It’s something we’ve talked about but not particularly looking for a patch.
When an entity like “foo” exists in numerous, ordered forms, it feels superfluous to name intermediate specs, and edges on “types”. I don’t want that extra, unnecessary complexity in my programs, so I’m looking for a way to define a “foo” as a succession of small transformations, where the phases (minor transforms) are named loosely, abstractly. One place to define all of the successions of miniature transforms is better than enshrining stronger, named entities. The names wind up feeling forced.
Coalescing specs into logical, ordered groupings feels valuable if only to avoid the naming of tiny-delta intermediates.
I think I'm getting the hang of test/check and custom generators, but I'm getting this oddball response from one of my fdef's: https://github.com/mathpunk/simplexity/blob/complexes/src/simplexity/core.clj#L70
The problem seems to be with your :fn
spec on dim
. The reason the examples work e.g. (dim (complex []))
is that they don’t run the :fn
code
It looks like the issue with the :fn
is that :ret
does not contain the value, it contains the conformed value e.g. not -1
, but rather [:empty -1]
I think this will avoid the exceptions, although the definition of dim
still fails the :fn
test in some cases:
(s/fdef dim
:args (s/cat :complex ::complex)
:ret (s/or :nonempty nat-int?
:empty #(= -1 %))
:fn #(and (number? (-> % :ret last))
(= (size (-> % :args :complex))
(+ (-> % :ret last) 1))))
FWIW, if you want to test out your fn
spec outside of check try https://github.com/jeaye/orchestra
@bbrinck Ah ha! I forgot about conformance.... aaaagain. And orchestra looks useful, much obliged
What's really baking my noodle is, there are a few things I can think of that might just be plain broke in the way I'm writing this, but, it would be broke with MUCH smaller examples than I seem to be getting as examples of failing results
I'm trying to define different specs for different implementations of a protocol, which I don't know if it's even possible. This code passes my example tests, but when I try and test/check
any of the functions, I just get an empty sequence: https://github.com/mathpunk/simplexity/blob/complexes/src/simplexity/simplex.clj
The problem I'm trying to solve is: A simplex is a special case of a complex. It would be nice to construct a simplex by going (simplex [0 1 2])
and a general complex by going (complex [[0 1 2] [2 3] [4 5 6]])
That is, construct a simplex from a collection of vertices, and a complex from a collection of (maximal) simplexes
I haven’t tried it myself, but the advice I’ve heard is that protocols should be internal implementation details and you should spec wrapper functions, which become the public-facing API.
In this case, you’d have a spec for the wrapper function. I’m not sure that it’d need to be different though - if complex
is the general case, could the work in terms of complex
? I’m not sure
You could certainly create a generator that creates either simplex or complex values though, and use that
Try wrapping dim
in another function e.g. (defn dim1 [x] (dim x))
, then write spec for that. test/check
works for me on dim1
(poorly named, of course 🙂 )
You can’t spec protocol functions
Why is the predicate function in the below error message :clojure.spec.alpha/unknown
?
(s/assert nat-int? -1)
ExceptionInfo Spec assertion failed
val: -1 fails predicate: :clojure.spec.alpha/unknown
clojure.core/ex-info (core.clj:4739)
I need to wrap with s/spec
?
(s/assert (s/spec nat-int?) -1)
ExceptionInfo Spec assertion failed
val: -1 fails predicate: nat-int?
clojure.core/ex-info (core.clj:4739)
That seems asymmetrical with the rest of Spec's API -- you can pass a Spec kw, predicate, or Spec obj.wrapping with s/spec bypasses it