 4clojure Double Down question

This pertains to question #15 on 4clojure “Double Down.” Original problem link here: https://www.4clojure.com/problem/15

My goal

My goal is to evaluate: “Do all the statements evaluate to true?” If yes, return true, else return false. In short, I want to write a single expression that will run all the test cases at once.

Ps. I have written this question post backwards on purpose because I think question 3 is the best question, but for those who want to see my thought process in more detail, they can work their way to 3 from 1 or 2. Sorry and thank you 3. Last question update:

Is it possible to tweak “example B” so that it works as desired? If so, how?

2. Updated question:

For what cases is every? true? appropriate, and what cases is every-pred true? appropriate? I have a hunch that, semantically speaking, every? takes one predicate to evaluate over a collection of values (ie. non-predicates), whereas, every-pred true? takes many predicates and simply asks. I think my brain has been scrambled…

1. Initial question:

Why does this work as expected…

;; example A
(and (= (#(* % 2) 2) 4)
(= (#(* % 2) 3) 6)
(= (#(* % 2) 11) 22)
(= (#(* % 2) 7) 14))
;; => true

… whereas the following simply returns an error:

;; example B
(every? true?
((= (#(* % 2) 2) 4)
(= (#(* % 2) 3) 6)
(= (#(* % 2) 11) 22)
(= (#(* % 2) 7) 14)))
;; => class java.lang.Boolean cannot be cast to class clojure.lang.IFn

… Upon some further reflection and research, I found this:

;; example C
((every-pred true?)
(= (#(* % 2) 2) 4)
(= (#(* % 2) 3) 6)
(= (#(* % 2) 11) 22)
(= (#(* % 2) 7) 14))
;; => true

… which appears to work as desired In short, I’d like to understand why “example B” gives an error, and if there was a better (clearer or simpler) way to solve for my personal challenge than examples A and C.

It looks like you got tripped up by evaluation semantics and order.
In case 2, read the error message:

;; => class java.lang.Boolean cannot be cast to class clojure.lang.IFn

The compiler thinks you’re trying to use a boolean as a function. Are you?
Let’s evaluate the expression step by step as Clojure would:

(every?
true?
((= (#(* % 2) 2) 4)
(= (#(* % 2) 3) 6)
(= (#(* % 2) 11) 22)
(= (#(* % 2) 7) 14)))
;;;
(every?
true?
((= (f 2) 4)
(= (f 3) 6)
(= (f 11) 22)
(= (f 7) 14)))
;;;
(every?
true?
((= 4 4)
(= 6 6)
(= 22 22)
(= 14 14)))
;;;
(every?
true?
(true true true true))

This is where you get a run time exception, you have a boolean in a call position and the emitted code is trying to call it as a function. No good.
Literal lists = evaluation.
The solution is to use literal vectors:

(every?
true?
[(= (#(* % 2) 2) 4)
(= (#(* % 2) 3) 6)
(= (#(* % 2) 11) 22)
(= (#(* % 2) 7) 14)])

This does what you expect.
It is best to use and here because it does not evaluate its arguments eagerly (it’s a macro, not a function).
every-pred works almost by accident, it returns a function which you then call on a bunch of values which are true. The function is true if all the combinations of the provided predicates and values are true. The only predicate is true? and all the values are true, so it works.
There are a few other solutions you can find if you use a vector.

2 Likes