How to make function validation to return true only based on arity, ignoring the output of the function? So I have something like this:
(-> [:=> [:cat :any] :any]
(malli/schema {::malli/function-checker malli-generator/function-checker})
(malli/validate (fn [x] (nth [0 1] x)))
And this returns false. In humanize version :error is nil.
I would expect it to return true, because there is one parameter and I don't care about output.
(-> [:=> [:cat :any] :any]
(malli/schema {::malli/function-checker malli-generator/function-checker})
(malli/validate (fn [x] x))
For example this works as expected and returns true.
I assume the former version can't predict what an output is because I call a function inside of it. But I don't care about output, that's why I said :any.
Is there a way to check only arity?I donβt rememeber. Future-engineered option that I have never used myself.
I'm not sure what Mateusz was after, but it looks like :scope is only available when instrumenting, that is, when somebody is calling the function anyway. I think Mateusz was after validating functions before calling them?
as data
ok, so the :scope is not used in function-checker..
.. but in wrapping around it, e.g. instrument
I guess you could make your own function-checker?
the problem with your first example is that malli-generator/function-checker calls your function with inputs like nil, which causes an exception, which causes the function-checker to reject the function
the reason why it's not in malli by default is because detecting the arity of a function is a bit tricky in clojure and impossible in clojurescript
here's a version that works for simple cases:
user=> (defn my-function-checker [?schema _opts] (fn [f] (when-not (= (:arity (malli/-function-info ?schema)) (arg-count f)) {::malli/result :wrong-arity :result :wrong-arity})))
#'user/my-function-checker
user=> (malli/explain (malli/schema [:=> [:cat :any] :any] {::malli/function-checker my-function-checker}) (fn [x] (nth [0 1] x)))
nil
user=> (malli/explain (malli/schema [:=> [:cat :any] :any] {::malli/function-checker my-function-checker}) (fn [x y] (nth [0 1] x)))
{:schema [:=> [:cat :any] :any], :value #object[user$eval6147$fn__6148 0x1fd0ae78 "user$eval6147$fn__6148@1fd0ae78"], :errors ({:path [], :in [], :schema [:=> [:cat :any] :any], :value #object[user$eval6147$fn__6148 0x1fd0ae78 "user$eval6147$fn__6148@1fd0ae78"], :check {:malli.core/result :wrong-arity, :result :wrong-arity}})}using this not-at-all robust arg-count from stackoverflow:
(defn arg-count [f]
{:pre [(instance? clojure.lang.AFunction f)]}
(-> f class .getDeclaredMethods first .getParameterTypes alength))https://stackoverflow.com/questions/1696693/clojure-how-to-find-out-the-arity-of-function-at-runtime
Great answer @joel.kaasinen! There is :scope option, which can be narrowed to check any of :input, :output or :guard. If that is only set to :input, it would only check arity and type of input I think. Might still fail on the function invocation with nil thou.
https://github.com/metosin/malli/blob/master/src/malli/core.cljc#L2803
is :scope also available when checking a schema that includes function values? something like {:callback (fn [a b] ...)}? or only when instrumenting defns?