Skip to content

Instantly share code, notes, and snippets.

@ChrisPenner
Created August 23, 2017 14:32
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ChrisPenner/11997de28e2e9adb6af31060a4828d66 to your computer and use it in GitHub Desktop.
Save ChrisPenner/11997de28e2e9adb6af31060a4828d66 to your computer and use it in GitHub Desktop.
Heyting Algebra Validation
const all = (...preds) => (obj) => preds.map(f => f(obj)).reduce((a, b) => a && b, true)
const any = (...preds) => (obj) => preds.map(f => f(obj)).reduce((a, b) => a || b, false)
const oneOf = (...preds) => (obj) => preds.map(f => f(obj)).reduce((a, b) => a ? !b : b, false)
const has = (prop) => (obj) => obj[prop] !== undefined
const not = (pred) => (obj) => !pred(obj)
const equals = (prop, val) => (obj) => obj[prop] === val
const implies = (f, g) => (obj) => !f(obj) || g(obj);
const validate = all(implies(has('selectedIndex'), equals('isOpen', true)))
validate({}) // true; passes all 'implications'
validate({'selectedIndex': 3}) // false; isOpen !== true!
validate({'selectedIndex': 3, isOpen: true}) // true; passes all implications
// more complex example
const complexValidate = all(
implies(equals('mode', 'indexed'),
all(
has('selectedIndex'),
obj => obj['selectedIndex'] <= 5
)
),
implies(equals('mode', 'disabled'), not(has('selectedIndex')))
)
@DrBoolean
Copy link

I know you know Chris, but for readers, this lacks some of prebuilt abstractions like foldMap on a List, setoid on Map, and a few monoid instances (Conj/Disj) which would knockout most of lines 1-6

@ChrisPenner
Copy link
Author

@DrBoolean, yeah and if you're doing this in Purescript you can basically delete the entire thing and just use standard &&, || and => over predicates themselves! Js is getting there eventually haha.

@matthieubulte
Copy link

Stealing the hack from 2ality you can (almost) have it like in Purescript
using +/* instead of &&/||

// see https://gist.github.com/matthieubulte/53ed96c5c5ee2297347e730804486918

const complexValidate =
  implies(
    equals('mode', 'indexed'),
    has('selectedIndex') * (obj => obj['selectedIndex'] <= 5)
  )
  * implies(equals('mode', 'disabled'), not(has('selectedIndex')));

mkP(complexValidate)({'mode':'enabled', 'selectedIndex':3}) // = true

😉

@rostero1
Copy link

I just discovered Heyting today. I'm confused as to what makes this a Heyting algebra? implies? Would not(not(equals(mode', 'indexed')) make this a boolean algebra?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment