Thank Alistair, but that does not really address my question. Alex suggested using :fn of fspec to check arity of a higher-order argument.
But I could not find a tool to check function arity. Also I doubt :fn is going to work since I'd expect it to be invoked /after/ the call - i. e. the call would fail before the arity check. Note that in your example you can only use spec/generic testing to check arity because you know the argument types. You can't test a generic higher order fn for just arity like this because the generator won't know the correct types to generate. On Monday, June 13, 2016 at 4:00:30 AM UTC+2, Alistair Roche wrote: > > Hi Leon, > > I think you're looking for fspec > <https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec/fspec>, > > unless I'm misunderstanding something. I wrote up an example > <https://gist.github.com/atroche/731f80376985773c60d5e943b38d8052> that > might be helpful. > > @Ryan thanks for starting this thread, and @Alex thanks for responding. > It's been an interesting discussion! > > Cheers, > > > On Monday, 13 June 2016 07:17:56 UTC+10, Leon Grapenthin wrote: >> >> Alex, thank you for the long and detailed response. >> >> The direct linking issue and Ryans last example make me wonder whether >> the hard rule >> >> "If A and B are both instrumented and if A ever calls B violating B's >> spec, A's spec is broken" >> >> holds? If so the direct-linking issue would probably be a non-concern >> since instrumentation within the standard library would not matter because >> one could assume that the core lib has been tested already against it's own >> specs. If the latter is true (I'm not quite sure) it would appear >> worthwhile to look for a counter-example against the former in the standard >> library. >> >> I'd highly appreciate if you could give an example for checking the arity >> of a passed in function since I don't see how to do that right now except >> for maybe using reflection? >> >> On Sunday, June 12, 2016 at 5:45:17 PM UTC+2, Alex Miller wrote: >>> >>> >>> On Sunday, June 12, 2016 at 9:22:24 AM UTC-5, Leon Grapenthin wrote: >>>> >>>> That looks great already. I'm also interested in what the official >>>> workflow for adding specs to core is going to be and whether contributions >>>> are desired. >>>> >>> >>> Still much to be determined about this but I expect that specs for core >>> will be provided and maintained by us, because while there are a lot of >>> obvious specs in core, there are also a lot of far more subtle ones. Some >>> of the predicates added in the latest alpha5 (seqable?, and the >>> simple/qualified ident/keyword/symbol) will not coincidentally be useful in >>> these. There are also a lot of cases where there is a judgement call on how >>> precise to be (any likely tradeoffs with testing, performance, conciseness). >>> >>> Also, there is a significant difference between specs for macros and >>> functions in core. Macro args specs will always be checked during >>> macroexpansion and this is a path toward better error messages for things >>> like defn, ns, etc. I think it would make a lot of sense to deliver those >>> with core. Specs for the functions in core are things you likely want >>> instrumented at dev time, not at prod time, and fights a bit with direct >>> linking. So, one option would be a dev build of Clojure, without direct >>> linking and with automatic instrumentation of the functions in core. >>> Another would be providing the core function specs externally or optionally >>> alongside Clojure. We've only begun discussing how this will wind up. >>> >>> I don't agree with the map spec provided because I expect the args and >>> ret to be seqable?, not sequential?. For example, you can map over sets, >>> which are seqable but not sequential. This kind of subtlety is why I expect >>> we will provide the specs for core. Once they exist, we'll be interested in >>> tickets on them of course. >>> >>> There are also interesting :fn specs you can write on map - you could >>> check that if the count of the coll args is 0 that the return is ifn? (a >>> transducer) and that if there is at least one coll then the ret is a coll. >>> If the colls are all finite, the return coll will have count equal to the >>> minimum of the count of the arg colls. I think the transducer/coll >>> difference is definitely worth spec'ing and would trigger errors in cases >>> where some forgets the coll and accidentally gets a transducer. Is the >>> cardinality check worth it? Probably not. >>> >>> identity could have a :fn spec that checks that the input and output are >>> identical. That's really the only thing you care about (other than the >>> cardinality of the input). Is this spec really helping you though? Not >>> every spec pays for it's weight and this may be one that isn't worth doing. >>> >>> >>>> The last example seems like it could be better because the user has to >>>> infer how identity was called within map. >>>> >>>> So what we'd want is a codependent spec where we can say if you give N >>>> sequences you have to give a fnN. Is this possible with the current ops? >>>> >>> >>> Yes, with fspec - you could have a :fn spec on map that checked that the >>> arity of the fn passed to map matched the number of colls you were passed. >>> That would be better here than the identity spec. >>> >>> >>>> >>>> >>>> On Sunday, June 12, 2016 at 3:52:33 PM UTC+2, Ryan Fowler wrote: >>>>> >>>>> Is there an effort to write specs for Clojure's core namespaces? >>>>> Apologies >>>>> if this has already been addressed. >>>>> >>>>> I've been tinkering with trivial (and probably wrong) fdefs on >>>>> clojure.core/map and clojure.core/identity. It seems that the spec >>>>> exception messages are way better than what we have now. >>>>> >>>>> Code is here: >>>>> https://gist.github.com/ryfow/69a64e966d48258dfa9dcb5aa74005eb >>>>> <https://www.google.com/url?q=https%3A%2F%2Fgist.github.com%2Fryfow%2F69a64e966d48258dfa9dcb5aa74005eb&sa=D&sntz=1&usg=AFQjCNF-D1x8PJNLKRUrdziNcKrzqh87LQ> >>>>> >>>>> >>>>> ========================================================= >>>>> Before instrumenting clojure.core/map >>>>> ========================================================= >>>>> Form: (into [] (map nil [1 2 3] [1 2 3])) >>>>> Exception Class: java.lang.NullPointerException >>>>> Message: nil >>>>> >>>>> Form: (into [] (map 1 [1 2 3] [1 2 3])) >>>>> Exception Class: java.lang.ClassCastException >>>>> Message: java.lang.Long cannot be cast to clojure.lang.IFn >>>>> >>>>> Form: (into [] (map identity 4)) >>>>> Exception Class: java.lang.IllegalArgumentException >>>>> Message: Don't know how to create ISeq from: java.lang.Long >>>>> >>>>> ========================================================= >>>>> After instrumenting clojure.core/map >>>>> ========================================================= >>>>> Form: (into [] (map nil [1 2 3] [1 2 3])) >>>>> Exception Class: clojure.lang.ExceptionInfo >>>>> Message: Call to #'clojure.core/map did not conform to spec: >>>>> In: [0] val: nil fails at: [:args :fn] predicate: ifn? >>>>> :clojure.spec/args (nil [1 2 3] [1 2 3]) >>>>> >>>>> >>>>> Form: (into [] (map 1 [1 2 3] [1 2 3])) >>>>> Exception Class: clojure.lang.ExceptionInfo >>>>> Message: Call to #'clojure.core/map did not conform to spec: >>>>> In: [0] val: 1 fails at: [:args :fn] predicate: ifn? >>>>> :clojure.spec/args (1 [1 2 3] [1 2 3]) >>>>> >>>>> >>>>> Form: (into [] (map identity 4)) >>>>> Exception Class: clojure.lang.ExceptionInfo >>>>> Message: Call to #'clojure.core/map did not conform to spec: >>>>> In: [1] val: 4 fails at: [:args :seq] predicate: sequential? >>>>> :clojure.spec/args (#object[clojure.core$identity 0x15a04efb >>>>> "clojure.core$identity@15a04efb"] 4) >>>>> >>>>> >>>>> ========================================================= >>>>> Before instrumenting clojure.core/identity >>>>> ========================================================= >>>>> Form: (into [] (map identity [1 2 3] [1 2 3])) >>>>> Exception Class: clojure.lang.ArityException >>>>> Message: Wrong number of args (2) passed to: core/identity >>>>> >>>>> ========================================================= >>>>> After instrumenting clojure.core/identity >>>>> ========================================================= >>>>> Form: (into [] (map identity [1 2 3] [4 5 6])) >>>>> Exception Class: clojure.lang.ExceptionInfo >>>>> Message: Call to #'clojure.core/identity did not conform to >>>>> spec: >>>>> In: [1] val: (4) fails at: [:args] predicate: (cat :one-argument >>>>> identity), Extra input >>>>> :clojure.spec/args (1 4) >>>>> >>>>> >>>>> -- 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.