a contracts-programming library for Clojure

the relationship between a class and its clients as a formal agreement, expressing each party's rights and obligations

As you saw in the description of `defconstrainedfn`

Trammel allows you to create functions with a localized and dependent contract. However, there may be circumstances where the separation of contract and constrained function is preferred. Take for example, a simple `slope`

function:

`(defn sqr [n] (* n n))`

Defining a separate contract for this function is a simple matter:

`(def sqr-contract (contract sqr-constraints "Defines the constraints for squaring" [n] [number? (not= 0 n) => pos? number?]))`

We can then define a constrained version of `sqr`

using Trammel’s `with-constraints`

macro:

`(def constrained-sqr (with-constraints sqr sqr-contract))`

(constrained-sqr 5);=> 25

(constrained-sqr -5);=> 25

(constrained-sqr 0); java.lang.AssertionError: Assert failed:

(not= 0 num)

(constrained-sqr :a); java.lang.AssertionError: Assert failed:

(number? num)

However, this constraint definition for `sqr`

, while accurate, is very broad. In fact, the software team developing software for the 8-bit Atari console would not be able to use `constrained-sqr`

as it is far too liberal. Therefore, they can define their own contract that further constrains `constrained-sqr`

:

`(def sqr-8bit-contract (contract atari-constraints "Defines the constraints for Atari 2600 sqr" [_] [number? => (< % 256)]))`

(def sqr-8bit (with-constraints constrained-sqr sqr-8bit-contract))

(sqr-8bit 5);=> 25

(sqr-8bit 0); java.lang.AssertionError: ; Assert failed: (not= 0 num)

And all appears to be in order – except:

`(sqr-8bit 100); java.lang.AssertionError:; Assert failed: (< % 256)`

That is, calling the function `sqr-8bit`

with `100`

causes a *post-condition* failure! The reason for this is because the underlying `sqr`

is the same old arbitrary-precision version when what we really want is a function that deals in only 8-bit values. There are two possible ways to do this:

- Create a version of
`sqr-8bit`

that does in fact deal in 8-bit values - Tighten the constraint on
`constrained-sqr`

further by applying another contract

`(def sqr-8bit-contract (contract atari-constraints "Defines the constraints for Atari 2600 sqr" [n] [(< n 16) integer? pos? => (< % 256)]))`

(def sqr-8bit (with-constraints constrained-sqr sqr-8bit-contract))

(sqr-8bit 15);=> 225

(sqr-8bit -5); java.lang.AssertionError: ; Assert failed: (pos? n)

(sqr-8bit 15.9687194); java.lang.AssertionError: ; Assert failed: (integer? n)

(sqr-8bit 16); java.lang.AssertionError: ; Assert failed: (< n 16)

Using `contract`

and `with-constraints`

you were able to tighten the constraints on both the pre- and post-conditions of the `sqr`

function. However, what if you wanted to relax the requirements? Stay tuned.