Can one make a predicate function from a Plumatic Schema? - clojure

I want to make a predicate function that when something matches schema X returns true, else false.

You can use schema/check which works like schema/validate but returns errors directly as a value instead of throwing exception or nil when no errors are found:
(schema/defschema string-vector
[schema/Str])
(defn str-vec? [arg]
(nil? (schema/check string-vector arg)))
(str-vec? ["hi"]) ; => true
(str-vec? ["hi" 5]) ; => false
There is also schema/checker which "compiles an efficient checker for schema":
(let [str-vec?-checker (schema/checker string-vector)]
(defn str-vec? [arg]
(nil? (str-vec?-checker arg))))

Perhaps not the most beautiful solution, but we can use schemas validate and catch the exception it throws on failures.
(schema/defschema string-vector
[schema/Str])
(defn str-vec? [arg]
(try (schema/validate string-vector arg)
true
(catch clojure.lang.ExceptionInfo e
false)))
(str-vec? ["hi"]) ; => true
(str-vec? ["hi" 5]) ; => false
Hopefully someone else can provide a better solution.

Related

A Clojure Spec for a predicate function

I want to write a specification for what it means for a function to be a predicate. There seems to be three ways to go about what a predicate is in the Clojure world, though most seem to agree that they should end in a question mark.
A function which takes one argument and returns true or false.
A function which takes one argument and returns true, false or nil.
A function which takes one argument and returns a truthey or falsey value.
Jira Ticket on what Predicate is.
EDIT: A predicate can also take multiple arguments as exemplified by contains?.
I think the most accurate spec for a predicate is:
(s/fspec :args (s/cat :v any?) :ret any?)
While predicates generally return true/false, there is no requirement for them to do so - the only required contract is that it takes one value and returns a value which will be treated as a logical truth value.
If I've understood clojure.spec/fdef correct it allows us to make specifications like the described in the question.
(spec/fdef ::predicate-1
:args (spec/cat :arg any?)
:ret boolean?)
Which we can test by passing it some examples which we know should pass or fail the test:
(spec/valid? ::predicate-1 boolean?) => true
(spec/valid? ::predicate-1 (fn [a] 5)) => false
(spec/valid? ::predicate-1 (fn [a] true)) => true
(spec/valid? ::predicate-1 (fn [a b] true))=> false
(spec/valid? ::predicate-1 #(= 10 %)) => true
(spec/valid? ::predicate-1 (fn [a] nil)) => false
For defenition nr. 2:
(spec/fdef ::predicate-2
:args (spec/cat :arg any?)
:ret (spec/nilable boolean?))
(spec/valid? ::predicate-2 (fn [a] nil)) => true
And for nr. 3 any function which takes one argument is valid since everything in clojure is either truthy or falsey.
(spec/fdef ::predicate-3
:args (spec/cat :arg any?)
:ret any?)
(spec/valid? ::predicate-3 identity) => true
(spec/valid? ::predicate-3 str) => true
One interesting thing we then seem to be able to do is have spec generate such functions for us:
(let [p (gen/generate (spec/gen ::pedicate-1))]
(clojure.string/join
" " [(p 0) (p 1) (p -1) (p nil) (p 'a) (p :a) (p (fn [a] a))]))
=> "false true true false true false false"
And out of that we can perhaps try to guess what the generated function does. But without being able to see the source we'll have a hard time checking whether our guess was correct or not.

How to test in Clojure if any given value is not-empty collection?

I need a predicate which returns logically true if the given value is a not-empty collection and logically false if it's anything else (number, string etc.).
And more specifically, that the predicate won't throw the IllegalArgumentException if applied to single number, or string.
I came up with the following function, but I'm wondering if there is some more idiomatic approach?
(defn not-empty-coll? [x]
(and (coll? x) (seq x)))
This will satisfy following tests:
(is (not (not-empty-coll? nil))) ;; -> false
(is (not (not-empty-coll? 1))) ;; -> false
(is (not (not-empty-coll? "foo"))) ;; -> false
(is (not (not-empty-coll? []))) ;; -> nil (false)
(is (not (not-empty-coll? '()))) ;; -> nil (false)
(is (not (not-empty-coll? {}))) ;; -> nil (false)
(is (not-empty-coll? [1])) ;; -> (1) (true)
(is (not-empty-coll? '(1))) ;; -> (1) (true)
(is (not-empty-coll? {:a 1})) ;; -> ([:a 1]) (true)
EDIT: A potential use case:
Let's say we need to process some raw external data which are not (yet) under our control. Input could be for example a collection which contains either primitive values, or nested collections. Other example could be a collection holding some inconsistent (maybe broken?) tree structure. So, we can consider mentioned predicate as first line data cleaning.
Otherwise, I agree with comments that is better to explicitly separate and process collection and non-collection data.
How about using Clojure protocols and type extensions to solve this?
(defprotocol EmptyCollPred
(not-empty-coll? [this]))
(extend-protocol EmptyCollPred
Object
(not-empty-coll? [this] false)
nil
(not-empty-coll? [this] false)
clojure.lang.Seqable
(not-empty-coll? [this] (not (empty? (seq this)))))
(is (not (not-empty-coll? nil))) ;; -> false
(is (not (not-empty-coll? 1))) ;; -> false
(is (not (not-empty-coll? "foo"))) ;; -> false
(is (not (not-empty-coll? []))) ;; -> nil (false)
(is (not (not-empty-coll? '()))) ;; -> nil (false)
(is (not (not-empty-coll? {}))) ;; -> nil (false)
(is (not-empty-coll? [1])) ;; -> (1) (true)
(is (not-empty-coll? '(1))) ;; -> (1) (true)
(is (not-empty-coll? {:a 1})) ;; -> ([:a 1]) (true)
Maybe it would be cleaner to extend just String and Number instead of Object - depends on what do you know about the incoming data. Also, it would be probably better to filter out nils beforehand instead of creating a case for it as you see above.
Another - conceptually similar - solution could use multimethods.
As suggested in the comments, I would consider calling not-empty? with a non-collection argument to be an invalid usage, which should generate an IllegalArgumentException.
There is already a function not-empty? available for use in the Tupelo library. Here are the unit tests:
(deftest t-not-empty
(is (every? not-empty? ["one" [1] '(1) {:1 1} #{1} ] ))
(is (has-none? not-empty? [ "" [ ] '( ) {} #{ } nil] ))
(is= (map not-empty? ["1" [1] '(1) {:1 1} #{1} ] )
[true true true true true] )
(is= (map not-empty? ["" [] '() {} #{} nil] )
[false false false false false false ] )
(is= (keep-if not-empty? ["1" [1] '(1) {:1 1} #{1} ] )
["1" [1] '(1) {:1 1} #{1} ] )
(is= (drop-if not-empty? ["" [] '() {} #{} nil] )
["" [] '() {} #{} nil] )
(throws? IllegalArgumentException (not-empty? 5))
(throws? IllegalArgumentException (not-empty? 3.14)))
Update
The preferred approach would be for a function to only receive collection parameters in a given argument, not a mixture scalar & collection arguments. Then, one only needs not-empty given the pre-knowledge that the value in question is not a scalar. I often use Plumatic Schema to enforce this assumption and catch any errors in the calling code:
(ns xyz
(:require [schema.core :as s] )) ; plumatic schema
(s/defn foo :- [s/Any]
"Will do bar to the supplied collection"
[coll :- [s/Any]]
(if (not-empty coll)
(mapv bar foo)
[ :some :default :value ] ))
The 2 uses of notation :- [s/Any] checks that the arg & return value are both declared to be a sequential collection (list or vector). Each element is unrestricted by the s/Any part.
If you can't enforce the above strategy for some reason, I would just modify your first approach as follows:
(defn not-empty-coll? [x]
(and (coll? x) (t/not-empty? x)))
I'm hoping you know at least a little about the param x so the question becomes: Is x a scalar or a non-empty vector. Then you could say something like:
(defn not-empty-coll? [x]
(and (sequential? x) (t/not-empty? x)))

A less cumbersome pattern for checking function parameters for nil in Clojure without throwing an assertion?

This was asked here, but the answers are all unacceptable.
I'm trying to apply some defensive programming techniques to clojure and I'm finding some things cumbersome.
Like checking function parameters:
(defn my-tolower [s]
(if (nil? s) nil
(.toLowerCase s)
))
Is there a cleaner way to do this?
I'm aware of :pre, but that throws an exception.
It seems you simply want some->, no?
(defn my-tolower [s]
(some-> s .toLowerCase))
(my-tolower "HELLO") => "hello"
(my-tolower nil) => nil
or just inline it without the wrapper function:
(some-> "HELLO" .toLowerCase) => "hello"
(some-> nil .toLowerCase) => nil
Since nil is falsey you could use when:
(when s (.toLowerCase s))
if you want the test you could use some? instead of nil?:
(if (some? s) (.toLowerCase s))
there are other aproaches too:
fnil, probably what I'd do
clojure.core/fnil
([f x] [f x y] [f x y z])
Takes a function f, and returns a function that calls f, replacing
a nil first argument to f with the supplied value x. Higher arity
versions can replace arguments in the second and third
positions (y, z). Note that the function f can take any number of
arguments, not just the one(s) being nil-patched.
provide a default value for a nil accepting fn. /
(let [f (fnil str/lower-case "")]
(f nil))
""
or catching the NPE
(let [f str/lower-case]
(try (f nil)
(catch NullPointerException ne nil)))
""
or just str
(.toLowerCase (str nil))
""
alternativly defprotocol and extend-protocol for nil maybe

Clojure not nil check

In Clojure nil? checks for nil. How does one check for not nil?
I want to do the Clojure equivalent of the following Java code:
if (value1==null && value2!=null) {
}
Follow-up: I was hoping for a not nil check instead of wrapping it with not. if has a if-not counterpart. Is there such a counterpart for nil??
After Clojure 1.6 you can use some?:
(some? :foo) => true
(some? nil) => false
This is useful, eg, as a predicate:
(filter some? [1 nil 2]) => (1 2)
Another way to define not-nil? would be using the complement function, which just inverts the truthyness of a boolean function:
(def not-nil? (complement nil?))
If you have several values to check then use not-any?:
user> (not-any? nil? [true 1 '()])
true
user> (not-any? nil? [true 1 nil])
false
If you are not interested in distinguishing false from nil, you can just use the value as the condition:
(if value1
"value1 is neither nil nor false"
"value1 is nil or false")
In Clojure, nil counts as false for the purposes of conditional expressions.
As a result (not x) works actually works exactly the same as as (nil? x) in most cases (with the exception of boolean false). e.g.
(not "foostring")
=> false
(not nil)
=> true
(not false) ;; false is the only non-nil value that will return true
=> true
So to answer your original question you can just do:
(if (and value1 (not value2))
...
...)
condition: (and (nil? value1) (not (nil? value2)))
if-condition: (if (and (nil? value1) (not (nil? value2))) 'something)
EDIT:
Charles Duffy provides correct custom definition for not-nil?:
You want a not-nil? Easily done: (def not-nil? (comp not nil?))
If you want your test to return true when given false, then you need one of the other answers here. But if you just want to test that returns a truthy value whenever it's passed something other than nil or false, you can use identity. For example, to strip nils (or falses) from a sequence:
(filter identity [1 2 nil 3 nil 4 false 5 6])
=> (1 2 3 4 5 6)
You can try when-not :
user> (when-not nil (println "hello world"))
=>hello world
=>nil
user> (when-not false (println "hello world"))
=>hello world
=>nil
user> (when-not true (println "hello world"))
=>nil
user> (def value1 nil)
user> (def value2 "somevalue")
user> (when-not value1 (if value2 (println "hello world")))
=>hello world
=>nil
user> (when-not value2 (if value1 (println "hello world")))
=>nil
If you want a not-nil? function, then I'd suggest just defining it as follows:
(defn not-nil?
(^boolean [x]
(not (nil? x)))
Having said that it is worth comparing the usage of this to the obvious alternative:
(not (nil? x))
(not-nil? x)
I'm not sure that introducing an extra non-standard function is worth it for saving two characters / one level of nesting. It would make sense though if you wanted to use it in higher order functions etc.
One more option:
(def not-nil? #(not= nil %))

Single predicate to test for "self-evaluating" atoms in Clojure

At the home site of Clojure, there is the following statement:
Strings, numbers, characters, true,
false, nil and keywords evaluate to
themselves.
Is there a single combined predicate that tests for any of these, combining string?, number?, char?, true?, false?, nil?, and keyword?. Should I just use (complement symbol?)?
Maybe I'm missing something, but you could use the following to test for any of those conditions and return true if one is true:
(defn self-eval?
[x]
(or (string? x)
(number? x)
(char? x)
(keyword? x)
(true? x)
(false? x)
(nil? x)))
It's easy enough to write a macro that asks "does the given expression evaluate to itself". In fact this is a good example of tasks that can only be done with a macro because they need to see the argument both evaluated and unevaluated.
(defmacro selfp [a] `(= ~a (quote ~a)))
#'user/selfp
user> (selfp 1)
true
user> (selfp +)
false
user> (selfp [1 2])
true
user> (selfp '(+ 1 2 3))
false
While strings, numbers, characters, keywords, and the booleans are all self-evaluating, other things such as [1 2] are as well,so this may not be a useful test in general.
Another option is to create a function that uses a map:
(defn myclassifier? [x]
(let [types-I-care-about #{java.lang.Sring ...}]
(if (types-I-care-about (type x))
true
false)))
Another option which may have better performance is to use java's dynamism:
(extend-type Object
IMyClassifier
(myclassifier? [x]
(let [c (.getClass x)]
(if (types-I-care-about (type c))
(do
(extend-type (.getClass x)
IMyClassifier
(myclassifier? [x] true))
true)
false))))
where types-I-care-about is a set of types you care about.