title: clojure-spec: Unable to get function's postcondition right
body: <p>I'm trying <a href="https://clojure.org/guides/spec" rel="nofollow noreferrer">clojure spec</a> on a simple function that computes the "neighbours" of a (row,col) position in a square matrix. For example for the 4x4 matrix given below, the neighbours of cell (1,1) shall be: (0,1), (1,0), (1,2), (2,1). The neighbours of cell (4,3), which is not even in the matrix' range, shall be (3,3) etc. </p>
  
  <p><a href="https://i.stack.imgur.com/Ve07M.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Ve07M.png" alt="4x4 square matrix and two positions with their neighbours"></a></p>
  
  <p>The function's input is the size of the matrix and the (row,col) of the position of interest. The output is a collection of (row,col) of the neighbours. This collection can be empty if there are no neighbours.</p>
  
  <p>This problem can be found in "The Joy of Clojure, 2nd editions, page 94; but this code is modified because the original was too compact for me. Then I tried to spec it and check the spec in the <code>:pre</code> and <code>:post</code> parts.</p>
  
  <p>However, I don't get the <code>:post</code> part to work. When I run the test cases, I get:</p>
  
  <pre><code>java.lang.ClassCastException: java.lang.Boolean cannot be cast
  to clojure.lang.IFn
  </code></pre>
  
  <p>What to change?</p>
  
  <pre><code>(require '[clojure.spec.alpha :as s]
           '[clojure.test       :as t])
  
  ; ===
  ; Specs
  ; ===
  
  (s/def ::be-row-col
         (s/coll-of integer? :count 2 :kind sequential?))
  (s/def ::be-square-matrix-size
         (s/and integer? #(&lt;= 0 %)))
  (s/def ::be-row-col-vector
         (s/and (s/coll-of ::be-row-col) (s/int-in-range? 0 5 #(count %))))
  
  ; ===
  ; Function of interest
  ; ===
  
  (defn neighbors [sqmsz rc]
  
       {:pre  [(s/valid? ::be-row-col rc)
               (s/valid? ::be-square-matrix-size sqmsz)] 
        :post [(s/valid? ::be-row-col-vector %)]
       }
  
       (let [ cross             [[-1 0] [1 0] [0 -1] [0 1]]
              in-sq-matrix?     (fn [x]
                                    (and (&lt;= 0 x) (&lt; x sqmsz)))
              in-sq-matrix-rc?  (fn [rc]
                                    (every? in-sq-matrix? rc))
              add-two-rc        (fn [rc1 rc2]
                                    (vec (map + rc1 rc2)))
              get-rc-neighbors  (fn [rc]
                                    (map (partial add-two-rc rc) cross)) ]
          (filter in-sq-matrix-rc? (get-rc-neighbors rc))))
  
  ; ===
  ; Put a collection of [row col] into an expected form
  ; ===
  ; this is used to run the test code
  
  (defn formify [rc-coll]
     (let [ cmp (fn [rc1 rc2]
                    (let [ [r1 c1] rc1
                           [r2 c2] rc2 ]
                       (cond (&lt; r1 r2) -1  ; sort by row
                             (&gt; r1 r2) +1
                             (&lt; c1 c2) -1  ; then by column
                             (&gt; c1 c2) +1
                             true       0))) ]
        (vec (sort cmp rc-coll))))
  
  ; ===
  ; Testing
  ; ===
  
  (defn test-nb [ sqmsz rc expected txt ]
     (do
        (t/is (= (formify (neighbors sqmsz rc)) expected) txt)
     ))
  
  (test-nb  0  [0 0]  []  "Zero-size matrix, outside #1")    
  (test-nb  0  [1 1]  []  "Zero-size matrix, outside #2")    
  (test-nb  1  [0 0]  []  "One-size matrix, inside")    
  (test-nb  1  [1 0]  [[0 0]]  "One-size matrix, outside")    
  (test-nb  5  [0 0]  [[0 1] [1 0]]  "Testing top left")    
  (test-nb  5  [1 0]  [[0 0] [1 1] [2 0]]  "Testing left edge")    
  (test-nb  5  [1 1]  [[0 1] [1 0] [1 2] [2 1]]  "Testing middle #1")    
  (test-nb  5  [2 2]  [[1 2] [2 1] [2 3] [3 2]]  "Testing middle #2")    
  (test-nb  5  [3 3]  [[2 3] [3 2] [3 4] [4 3]]  "Testing middle #3")    
  (test-nb  5  [4 4]  [[3 4] [4 3]]  "Testing btm right")    
  (test-nb  5  [5 5]  []  "Testing outside #1")    
  (test-nb  5  [5 4]  [[4 4]]  "Testing outside #2")    
  (test-nb  5  [4 3]  [[3 3] [4 2] [4 4]]  "Testing btm edge")
  </code></pre>