tags:

views:

54

answers:

2

(defn divisible [x y] (zero? (rem x y)))

  1. ((or (fn [x] (divisible x 3)) (fn [x] (divisible x 5))) 3)
  2. ((or (fn [x] (divisible x 3)) (fn [x] (divisible x 5))) 5)

the first expression evals to true but not the second one why?

  • can some on explain whats going on here?
+1  A: 

You seem to think that or somehow combines the functions that it receives as arguments, but that's not the case. or can take any kind of values as arguments and simply returns the first one that is "truthy".

So (or (fn [x] (divisible x 3)) (fn [x] (divisible x 5))) returns (fn [x] (divisible x 3)) (because functions are "not nothing" and thus "truthy").

So when you do ((or (fn [x] (divisible x 3)) (fn [x] (divisible x 5))) something), you're really just doing ((fn [x] (divisible x 3)) something).

sepp2k
+4  A: 

An expression of the form (or foo bar) does not "glue together" two predicates into one compound predicate; it returns foo if it is truthy, else bar. In your code, (fn [x] (divisible x 3)) is of course truthy (the only falsey values are false and nil), so the whole thing is equivalent to

((fn [x] (divisible x 3)) 3)
((fn [x] (divisible x 3)) 5)

What you want to do is something like

(some #(apply % 3) [(fn [x] (divisible x 3)) (fn [x] (divisible x 5)])
(some #(apply % 5) [(fn [x] (divisible x 3)) (fn [x] (divisible x 5)])
              ; ^- here goes the thing being tested

In general,

(defn or-preds [& preds]
  (fn [& args]
    (some #(apply % args) preds)))

((or-preds (fn [x] (divisible x 3)) (fn [x] (divisible x 5))) 3)
((or-preds (fn [x] (divisible x 3)) (fn [x] (divisible x 5))) 5)
;; or simpler...
((or-preds #(divisible % 3) #(divisible % 5)) 3)
Michał Marczyk
* thanks a lot, I just didn't realize that the first function was returned immediately by or cause it got evaluated as truthy. * what I really needed was this #(or (divisible % 3) (divisible % 5))
Jigar