On testing predicate functions

I’m working through the Clojure syllabus, and hit a snag on the bird-watcher exercise.

I implemented day-without-birds? like

(defn day-without-birds? [birds]
  (some zero? birds))

But I had a failing test: the test is explicitly comparing the result to false, but some returns nil.

I submitted this function which is a pretty gross hack.

(defn day-without-birds? [birds]
  ; grrr: `some` returns nil if none found,
  ; but the test checks the result is _equal_ to false.
  (not (not (some zero? birds))))

(I was this close to submitting (if (some zero? birds) true false) but I just couldn’t bring myself to do that).

The tests for this task are

...
    (is (= true (bird-watcher/day-without-birds? [5 5 4 0 7 6 7])))))
...
    (is (= false (bird-watcher/day-without-birds? [5 5 4 1 7 6 7])))))

Can we change that to

...
    (is (bird-watcher/day-without-birds? [5 5 4 0 7 6 7]))))
...
    (is (not (bird-watcher/day-without-birds? [5 5 4 1 7 6 7])))))

And similarly for the odd-week? tests.

I realize the = true and = false versions are more explicit, but the nil result is an unpleasant test failure.

Or perhaps add a couple of helper functions:

(defn- truthy? [value] (if value true false))
(defn- falsey? [value] (if value false true))

and then the test assertions can be

    (is (truthy? (bird-watcher/day-without-birds? [5 5 4 0 7 6 7])))))
...
    (is (falsey? (bird-watcher/day-without-birds? [5 5 4 1 7 6 7])))))

@porkostomus what thinkest thou?

You could use boolean:

(defn day-without-birds? [birds]
  (boolean (some zero? birds)))

(day-without-birds? [5 5 4 5 7 6 7])
;;=> false
1 Like

There’s also true?

(defn day-without-birds? [birds]
  (true? (some zero? birds)))

These are good suggestions, but I think my original question remains. Is testing equality to false the right approach?

You are referring to the tests? If so, yes, the approach is correct. It is a language convention that functions ending in ? should return true or false.

Yeah, I got caught up by the nil thing too.

My original implementation

(defn day-without-birds? [birds]
  "Check if there's a day with no birds logged"
  (true? (some zero? birds)))

Mentored implemention with Bob

(defn day-without-birds? [birds]
  "Check if there's a day with no birds logged"
  (not (every? pos? birds)))

The original implementation is how I would have expected some to have actually work because true and false are logical opposites and nil seems to be the Java null. This exercise is tied to the Vectors syllabus concept which only requires the Basics concept. So true, false, and nil hadn’t been introduced at this point so I think using helper functions to test for false or nil would be reasonable.

1 Like