Short Circuiting Truth Test of Predicate Collection - clojure

Say there is the need to check if an argument passes one truth test of a given predicate collection.
codewise:
(fn [x]
(or (pred1 x) (pred2 x) (pred3 x) (pred4 x)))
due to the implementation of or, this short circuits after the first truthy value. As intended.
How can this be rewritten by using a collection of predicates:
[pred1 pred2 pred3 pred4]
A funky way would be:
(fn [x preds]
(some? ;; nil->false
(some true? (map #(% x) preds))))
It also turns out that this one does not short circuit. Might be due to Clojure's chunking of lazy sequences.
Can we do this better?

clojure has a some-fn function for that:
user> ((some-fn true? false? nil?) true)
true
user> ((some-fn false? nil?) true)
false
or for your case:
user> (defn any-pred? [x preds]
((apply some-fn preds) x))
another classic way is to do it recursively:
user> (defn any-pred? [x preds]
(when-let [[pred & preds] (seq preds)]
(or (pred x) (any-pred? x preds))))
user> (any-pred? true [false?])
nil
user> (any-pred? true [true?])
true
user> (any-pred? true [false? true?])
true
user> (any-pred? true [false? nil?])
nil
user> (any-pred? true [false? nil? true?])
true

I think it's map that's doing the chunking in your solution.
Try
(defn any-true? [preds]
(fn [x]
(loop [preds preds]
(and (seq preds)
(or ((first preds) x)
(recur (rest preds)))))))
((any-true? [odd? even?]) 3) ;true
((any-true? []) 3) ;nil
((any-true? [even?]) 3) ;nil
((any-true? [odd? #(/ % 0)]) 3) ;true
The last example shows that the evaluation is lazy.

When I need short circuit, I use reduce with reduced.
(defn any-valid? [w & pred-fn-coll]
(reduce (fn [v pf]
(if (pf w)
(reduced true)
v)) false pred-fn-coll))
(any-valid? 1 even? odd?)
;=> true
(any-valid? 1 even? even?)
;=> false

Alternatively,
(defn somep? [x [p & ps :as preds]]
(if-not (empty? preds)
(or (p x) (somep? x ps))))
or
(defn somep? [x [p & ps :as preds]]
(if-not (empty? preds)
(let [res (p x)]
(if-not res
(recur x ps)
res))))

Related

Clojure functions which perform symbolic simplification using 'and'

I am new to Clojure and I'm learning how to write a program that can simplify logical expressions (just 'and' for now to figure out how things work first). For example:
(and-simplify '(and true)) => true
(and-simplify '(and x true)) => x
(and-simplify '(and true false x)) => false
(and-simplify '(and x y z true)) => (and x y z)
I already knew how to simplify two arguments, that everything I can do right now is:
(defn and-simplify []
(def x (and true false))
println x)
(and-simplify)
I've read this post and tried to modify my code a little bit but it doesn't seem to get me anywhere:
(defn and-simplify [&expr]
(def (and &expr))
)
What is the correct way that I should have done?
Here's my take on it.
(defn simplify-and
[[op & forms]]
(let [known-falsy? #(or (false? %) (nil? %))
known-truthy? #(and (not (symbol? %))
(not (seq? %))
(not (known-falsy? %)))
falsy-forms (filter known-falsy? forms)
unknown-forms (remove known-truthy? forms)]
(if (seq falsy-forms)
(first falsy-forms)
(case (count unknown-forms)
0 true
1 (first unknown-forms)
(cons op unknown-forms)))))
(comment (simplify-and `(and true 1 2 a)))
However, we can write a more generic simplify that uses multimethods to simplify lists, so that we can add more optimisations without modifying existing code. Here's that, with optimisations for and, or and + from clojure.core. This simplify only optimises lists based on namespace qualified names.
Check out the examples in the comment form. Hope it makes sense.
(defn- known-falsy? [form]
(or (false? form) (nil? form)))
(defn- known-truthy? [form]
(and (not (symbol? form))
(not (seq? form))
(not (known-falsy? form))))
(declare simplify)
(defmulti simplify-list first)
(defmethod simplify-list :default [form] form)
(defmethod simplify-list 'clojure.core/and
[[op & forms]]
(let [forms (mapv simplify forms)
falsy-forms (filter known-falsy? forms)
unknown-forms (remove known-truthy? forms)]
(if (seq falsy-forms)
(first falsy-forms)
(case (count unknown-forms)
0 true
1 (first unknown-forms)
(cons op unknown-forms)))))
(defmethod simplify-list 'clojure.core/or
[[op & forms]]
(let [forms (mapv simplify forms)
truthy-forms (filter known-truthy? forms)
unknown-forms (remove known-falsy? forms)]
(if (seq truthy-forms)
(first truthy-forms)
(case (count unknown-forms)
0 nil
1 (first unknown-forms)
(cons op unknown-forms)))))
(defmethod simplify-list 'clojure.core/+
[[op & forms]]
(let [{nums true non-nums false} (group-by number? (mapv simplify forms))
sum (apply + nums)]
(if (seq non-nums)
(cons op (cons sum non-nums))
sum)))
(defn simplify
"takes a Clojure form with resolved symbols and performs
peephole optimisations on it"
[form]
(cond (set? form) (into #{} (map simplify) form)
(vector? form) (mapv simplify form)
(map? form) (reduce-kv (fn [m k v] (assoc m (simplify k) (simplify v)))
{} form)
(seq? form) (simplify-list form)
:else form))
(comment
(simplify `(+ 1 2))
(simplify `(foo 1 2))
(simplify `(and true (+ 1 2 3 4 5 foo)))
(simplify `(or false x))
(simplify `(or false x nil y))
(simplify `(or false x (and y nil z) (+ 1 2)))
)

Clojure: Has anyone made a tool for visualizing the tree structure of your code?

I'm learning Clojure (my first LISP) and in learning about the idea of "code as data" inherent to LISPs I'm curious as to if anyone has ever built a tool that will read a program and build the abstract syntax tree in a visualizer for you - possibly pre and post macro expansion?
By this, I mean a graphical depiction of a tree in something like SVG.
Really, all you have to do is ' (quote) a form to get an AST of it. That's the beauty of lisps. Say you have the standard every? function:
(defn every?
"Returns true if (pred x) is logical true for every x in coll, else
false."
{:tag Boolean
:added "1.0"
:static true}
[pred coll]
(cond
(nil? (seq coll)) true
(pred (first coll)) (recur pred (next coll))
:else false))
Just quote it out to get a nested list of symbols:
; Notice the quote at the start!
'(defn every?
"Returns true if (pred x) is logical true for every x in coll, else
false."
{:tag Boolean
:added "1.0"
:static true}
[pred coll]
(cond
(nil? (seq coll)) true
(pred (first coll)) (recur pred (next coll))
:else false))
=>
(defn
every?
"Returns true if (pred x) is logical true for every x in coll, else\nfalse."
{:tag Boolean, :added "1.0", :static true}
[pred coll]
(cond (nil? (seq coll)) true (pred (first coll)) (recur pred (next coll)) :else false))
You can neaten it up a bit for visualization by using the standard clojure.pprint/pprint function (indentation indicates nesting):
(clojure.pprint/pprint
'(defn every?
"Returns true if (pred x) is logical true for every x in coll, else
false."
{:tag Boolean
:added "1.0"
:static true}
[pred coll]
(cond
(nil? (seq coll)) true
(pred (first coll)) (recur pred (next coll))
:else false)))
(defn
every?
"Returns true if (pred x) is logical true for every x in coll, else\n false."
{:tag Boolean, :added "1.0", :static true}
[pred coll]
(cond
(nil? (seq coll))
true
(pred (first coll))
(recur pred (next coll))
:else
false))
And you can get a post-macro expansion representation by feeding a call to macroexpand in there:
(clojure.pprint/pprint
(macroexpand
'(defn every?
"Returns true if (pred x) is logical true for every x in coll, else
false."
{:tag Boolean
:added "1.0"
:static true}
[pred coll]
(cond
(nil? (seq coll)) true
(pred (first coll)) (recur pred (next coll))
:else false))))
(def
every?
(clojure.core/fn
([pred coll]
(cond
(nil? (seq coll))
true
(pred (first coll))
(recur pred (next coll))
:else
false))))
If you're looking for something more than this, it's trivial to quote out some code then recursively do a search over it. You can change it into any format that you want.

Why applying seq on a LazySeq returns ChunkedCons?

(class (range 10))
;=> clojure.lang.LazySeq
(class (seq (range 10))
;=> clojure.lang.ChunkedCons
From my understanding, LazySeq is already an sequence, since:
(seq? (range 10))
;=> true
I guess I have an answer.
That's because using seq enforces the evaluation of the first element of LazySeq. Because seq returns nil when the collection & sequence is empty, it has to eval the element to decide that.
That's the exactly reason why rest is lazier than next, because (next s) is just (seq (rest s)).
To expand upon your answer (and because comments don't support new lines):
user=> (def r (range 10))
#'user/r
user=> (realized? r)
false
user=> (class r)
clojure.lang.LazySeq
user=> (def r2 (rest r))
#'user/r2
user=> (realized? r2)
ClassCastException clojure.lang.ChunkedCons cannot be cast to clojure.lang.IPending clojure.core/realized? (core.clj:6607)
user=> (class r2)
clojure.lang.ChunkedCons
user=> (realized? r)
true

Clojure local-variables

I want to create a function (thunk) that will return successive elements in a list. What is the best way to do this? I wrote this code based on an apparently flawed understanding of how local variables in clojure work:
(defn reader-for [commands]
(with-local-vars
[stream commands]
(fn []
(let
[r (var-get stream)]
(if (empty? r)
nil
(let
[cur (first r)
_ (var-set stream (rest r))]
cur))))))
In this code I get:
#<CompilerException java.lang.IllegalStateException: Var null/null is unbound. (Chapel.clj:1)>
which seems to suggest that with-local-vars is dynamically scoped. Is that true? Is there any lexically scoped alternative? Thanks for any help.
If you require mutable state, use one of the clojure reference types:
user=> (defn reader-for [coll]
(let [a (atom coll)]
(fn []
(let [x (first #a)]
(swap! a next)
x))))
#'user/reader-for
user=> (def f (reader-for [1 2 3]))
#'user/f
user=> (f)
1
user=> (f)
2
user=> (f)
3
user=> (f)
nil
Also, let is for lexical scoping, binding is for dynamic scoping.
Edit: the thread-safe version as pointed out by Alan.
(defn reader-for [coll]
(let [r (ref coll)]
#(dosync
(let [x (first #r)]
(alter r next)
x))))
And just for fun, a thread-safe version with atoms (don't do this):
(defn reader-for [coll]
(let [a (atom coll)]
(fn []
(let [ret (atom nil)]
(swap! a (fn [[x & xs]]
(compare-and-set! ret nil x)
xs))
#ret))))

Is there a function similar to "andmap" in clojure?

I want to apply a series of tests on my list and make sure that all the tests are passed.
Is there a function similar to "andmap" in Clojure?
You could use every?:
user=> (every? string? '("hi" 1))
false
Here's the documentation on every?.
Clojure 1.3 will add every-pred (and the related some-fn for the "or" version).
clojure.core/every-pred
([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
Takes a set of predicates and returns a function f that returns true if all of its
composing predicates return a logical true value against all of its arguments, else it returns
false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical false result against the original predicates.
A naive implementation might be:
(defn every-pred [& preds] (fn [& args] (every? #(every? % args) preds)))
but the actual implementation will have better performance.
I wrote andmap as a macro which takes predicates as its arguments and builds a function that "wraps an and around the predicates", i.e.,
(andmap integer? odd?)
==>
(fn [x] (and (integer? x)
(odd? x)))
(it doesn't expand to exactly this, but it expands to something equivalent to this)
This has the advantage that it shortcuircuts on the predicates so you can write
(every? (andmap integer? odd?) [1 3 "a string"])
without getting a runtime exception as you would get with Arthurs answer.
Here is the definition of andmap:
(defmacro andmap
([] `(fn [& x#] true))
([p & ps] `(fn [& x#] (and (apply ~p x#)
(apply (andmap ~#ps) x#)))))
It is also possible to define andmap as an function which also short-circuits on it's predicates due to lazyness:
(defn andmap [& ps]
(fn [& x]
(every? true? (map (fn [p] (apply p x)) ps))))
The predicates to andmap can take an arbitrary number of arguments, so it is possible to write
(map (andmap #(and (integer? %1)
(integer? %2))
#(and (odd? %1)
(even? %2))
<)
[1 3 9]
[2 6 "string"])
which evaluates to (true true false).
every? will ask "Does this one function return true for each member of the seq", which is close to what I think you are asking for. An improvement on every? would take a list of functions and ask "Are all these predicates true for every member of this seq".
Here is a first attempt:
(defn andmap? [data tests]
(every? true? (for [d data, f tests]
(f d))))
user> (andmap? '(2 4 8) [even? pos?])
true
user> (andmap? '(2 4 8) [even? odd?])
false