Last active
February 10, 2020 18:45
-
-
Save gordonbrander/dae1b87259331f7ceed192168527bcbd to your computer and use it in GitHub Desktop.
Racket-style contracts code sketch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simple runtime type checking. | |
export class ContractViolation extends Error {} | |
export const contract = predicate => value => { | |
if (predicate(value)) { | |
return value | |
} else { | |
throw new ContractViolation( | |
`Contract violation. Expected ${predicate}. Given ${value}.` | |
) | |
} | |
} | |
export const and = (ca, cb) => x => cb(ca(x)) | |
export const or = (ca, cb) => x => { | |
try { | |
return ca(x) | |
} catch (e) { | |
if (e instanceof ContractViolation) { | |
return cb(x) | |
} else { | |
throw e | |
} | |
} | |
} | |
export const any = x => x | |
export const number = contract(x => typeof x === 'number') | |
export const string = contract(x => typeof x === 'string') | |
export const nullish = contract(x => x == null) | |
export const array = contract(Array.isArray) | |
export const instance = t => contract(x => x instanceof t) | |
export const length = n => contract(x => x.length === n) | |
const lambda1 = (ca, cout) => func => a => | |
cout(func(ca(a))) | |
const lambda2 = (ca, cb, cout) => func => (a, b) => | |
cout(func(ca(a), cb(b))) | |
const lambda3 = (ca, cb, cc, cout) => func => (a, b, c) => | |
cout(func(ca(a), cb(b), cc(c))) | |
const lambda4 = (ca, cb, cc, cd, cout) => func => (a, b, c, d) => | |
cout(func(ca(a), cb(b), cc(c), cd(d))) | |
const lambda5 = (ca, cb, cc, cd, ce, cout) => func => (a, b, c, d, e) => | |
cout(func(ca(a), cb(b), cc(c), cd(d), ce(e))) | |
const lambda6 = (ca, cb, cc, cd, ce, cf, cout) => func => (a, b, c, d, e, f) => | |
cout(func(ca(a), cb(b), cc(c), cd(d), ce(e), cf(f))) | |
const lambda7 = (ca, cb, cc, cd, ce, cf, cg, cout) => func => | |
(a, b, c, d, e, f, g) => | |
cout(func(ca(a), cb(b), cc(c), cd(d), ce(e), cf(f), cg(g))) | |
const lambda8 = (ca, cb, cc, cd, ce, cf, cg, ch, cout) => func => | |
(a, b, c, d, e, f, g, h) => | |
cout(func(ca(a), cb(b), cc(c), cd(d), ce(e), cf(f), cg(g), ch(h))) | |
export const lambda = (...contracts) => { | |
const nargs = contracts.length - 1 | |
if (nargs === 1) { | |
return lambda1(...contracts) | |
} else if (nargs === 2) { | |
return lambda2(...contracts) | |
} else if (nargs === 3) { | |
return lambda3(...contracts) | |
} else if (nargs === 4) { | |
return lambda4(...contracts) | |
} else if (nargs === 5) { | |
return lambda5(...contracts) | |
} else if (nargs === 6) { | |
return lambda6(...contracts) | |
} else if (nargs === 7) { | |
return lambda7(...contracts) | |
} else if (nargs === 8) { | |
return lambda8(...contracts) | |
} else { | |
throw Error( | |
`Lambda contracts support up to 8 arguments. Given: ${contracts.length}` | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment