Namespaces

 
0.3.2 permalink Arrow_down_16x16

contract

fogus.me.trammel

  • (contract name docstring & constraints)
The base contract form returning a higher-order function that can then be partially
applied to an existing function to 'apply' a contract. Take for example a simple
contract that describes an expectation for a function that simply takes one or two
numbers and returns the double:

(def doubler-contract
(contract doubler
[x] [number? => (= (* 2 x) %)]

[x y] [(every? number? [x y]) => (= (* 2 (+ x y)) %)]))

You can then partially apply this contract with an existing function:

(def doubler (partial doubler-contract #(* 2 %)))
(def bad-doubler (partial doubler-contract #(* 3 %)))

And then running these functions will be checked against the contract at runtime:

(doubler 2)
;=> 4

(bad-doubler 2)
; java.lang.AssertionError: Assert failed: (= (* 2 x) %)

Similar results would occur for the 2-arity versions of `doubler` and `bad-doubler`.

While it's fine to use `partial` directly, it's better to use the `with-constraints` function
found in this same library.

If you're so inclined, you can inspect the terms of the contract via its metadata, keyed on
the keyword `:constraints`.

0 Examples top

Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source fogus/me/trammel.clj:100 top

(defmacro contract
  "The base contract form returning a higher-order function that can then be partially
   applied to an existing function to 'apply' a contract.  Take for example a simple
   contract that describes an expectation for a function that simply takes one or two
   numbers and returns the double:
   
    (def doubler-contract
       (contract doubler
         [x] [number? => (= (* 2 x) %)]

         [x y] [(every? number? [x y]) => (= (* 2 (+ x y)) %)]))

   You can then partially apply this contract with an existing function:

    (def doubler (partial doubler-contract #(* 2 %)))
    (def bad-doubler (partial doubler-contract #(* 3 %)))

   And then running these functions will be checked against the contract at runtime:

    (doubler 2)
    ;=> 4

    (bad-doubler 2)
    ; java.lang.AssertionError: Assert failed: (= (* 2 x) %)

   Similar results would occur for the 2-arity versions of `doubler` and `bad-doubler`.

   While it's fine to use `partial` directly, it's better to use the `with-constraints` function
   found in this same library.

   If you're so inclined, you can inspect the terms of the contract via its metadata, keyed on
   the keyword `:constraints`.
  "
  [name docstring & constraints]
  (let [raw-cnstr   (partition 2 constraints)
        arity-cnstr (for [[a c] raw-cnstr]
                      (build-constraints-map a c))
        fn-arities  (for [b arity-cnstr]
                      (build-contract b))]
    (list `with-meta 
          (list* `fn name fn-arities)
          `{:constraints (into {} '~arity-cnstr)})))
Vars in fogus.me.trammel/contract: defmacro gensym let list* name fn list apply concat hash-map into seq with-meta
Used in 0 other vars

Comments top

No comments for contract. Log in to add a comment.