| COPYING.txt | Initial commit | |
| README.md | Initial commit | |
| tinycontract.sls | Initial commit | |
A tiny library for contract-like type checks on Scheme procedures
Probably not ‘true’ contracts because they are not only enforced at module boundaries.
Uses continuation marks (SRFI 226) to only enforce output value type checks when doing so would not interfere with a tail call.
(lambda/contract <formals> (-> <input-contracts> <output-contracts>) <body>)
<input-contracts> --> <value-contract>
| (<value-contract> ...)
| (<value-contract ... . <value-contract>)
<output-contracts> --> <value-contract>
| (<value-contract> ...)
| (<value-contract ... . <value-contract>)
<value-contract> --> <expression>
There must be as many input contracts as formals. When called, each argument will be checked with the procedures resulting from the evaluation of the corresponding input contract expressions.
When the procedure is called outside of the tail position of a contracted procedure (be it the same procedure or another), the output values will additionally be checked with the procedures resulting from the evaluations of the corresponding output contract expressions.
The ‘rest’ value contract is applied to each rest value individually, in both input and output.
Trivial example
(define even->odd
(lambda/contract (n)
(-> (even?) (odd?))
(+ n 1)))
(even->odd 4) returns 5. (even->odd 5) is a violation.
Acknowledgements
The code that detects a tail call is based on Tony Garnock-Jones’s example.
Bugs
The <value-contract> expressions are evaluated anew every time the checks are run, instead of once when the procedure is created.
Probably many others. This is likely not a sensible approach to this problem.