Skip to content
marick edited this page Feb 20, 2013 · 12 revisions

Sometimes it's convenient to illustrate a fact with a table of values. For example, Conway's Life has rules for when cells are born, stay alive, or die. They look nice expressed as a table:

     (tabular
      (fact "The rules of Conway's life"
        (alive? ?cell-status ?neighbor-count) => ?expected)
      ?cell-status   ?neighbor-count   ?expected
      :alive         1                 FALSEY        ; underpopulation
      :alive         2                 truthy       
      :alive         3                 truthy
      :alive         4                 FALSEY        ; overpopulation
     
      ;; A newborn cell has three parents
      :dead          2                 FALSEY
      :dead          3                 truthy
      :dead          4                 FALSEY)

Note that you can capitalize falsey. FALSEY and TRUTHY are synonyms for the lowercase form. I find that using the capitalized form for one makes a tabular fact easier to read.

In case of a failure, the line number points to the prediction, as usual. But it's augmented by a description of which set of values caused the failure. For example, if alive? always returns false, the fact above will yield three failures:

     FAIL at (t_sweet.clj:237)
     With table substitutions: {?cell-status :alive, ?neighbor-count 2, ?expected truthy}
     Actual result did not agree with the checking function.
             Actual result: false
         Checking function: truthy
     FAIL at (t_sweet.clj:237)
     With table substitutions: {?cell-status :alive, ?neighbor-count 3, ?expected truthy}
     Actual result did not agree with the checking function.
             Actual result: false
         Checking function: truthy
     FAIL at (t_sweet.clj:237)
     With table substitutions: {?cell-status :dead, ?neighbor-count 3, ?expected truthy}
     Actual result did not agree with the checking function.
             Actual result: false
         Checking function: truthy

Details

Substitutions work with more than just plain values. For example, instead of using truthy and falsey, you can substitute the checking arrow:

     (tabular
      (fact "only two numbers have the same sum and square"
        (* ?n ?n) ?arrow (+ ?n ?n))
      ?n        ?arrow
      0         =>      
      2         =>
      ;; Failure cases
      1         =not=>
      ;; and so on
      )

Tabular facts behave exactly like regular facts. They can be turned into future facts:

     (tabular
      (future-fact (inc ?int) => ?int)
      ?int
      1)

They obey fact-wide prerequisites, setup/teardown, and so on.

You can have many predictions within the fact.

Doc strings (and other [metadata]) can be after the tabular if you find that more readable than after the fact.

     (tabular "increment works"
      (fact (inc ?int) => ?int)
      ?int
      1)
Clone this wiki locally