Skip to content

Instantly share code, notes, and snippets.

@halan
Last active March 13, 2020 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save halan/5000ddc557e2fb49e13a6c527ee4b317 to your computer and use it in GitHub Desktop.
Save halan/5000ddc557e2fb49e13a6c527ee4b317 to your computer and use it in GitHub Desktop.
Example of monads to manage validations
// base
const Valid = x => ({
map: f => Valid(f(x)),
chain: f => f(x),
bimap: ({valid}) => Valid(valid(x)),
cata: ({valid}) => valid(x)
})
const Wrong = x => ({
map: f => Wrong(x),
chain: f => Wrong(x),
bimap: ({wrong}) => Wrong(wrong(x)),
cata: ({wrong}) => wrong(x)
})
const validate = (pred, msgFn) => data =>
pred(data)
? Valid(data)
: Wrong(msgFn(data))
const isString = x =>
x.constructor === String
const hasKey = key => x =>
x && x.hasOwnProperty(key)
const validateKey = name =>
validate(hasKey(name), () => `${name} not found`)
const field = (validation, msgFn, name) => data =>
validateKey(name)(data)
.map(data => data[name])
.chain(validation)
.bimap({
wrong: err => msgFn(err),
valid: x => data
})
const chain = (a, b) =>
a.chain(b)
const validations = all => data =>
all.reduce(chain, Valid(data))
const stringField = name =>
field(
validate(isString, () => "isn't string"),
msg => `${name} ${msg}`,
name
)
// validators
const validateUser = validations([
stringField("name"),
stringField("team")
]);
const validateProfile = validations([
field(validateUser, msg => `user.${msg}`, "user"),
stringField("color")
]);
const printValidation = {
wrong: x => console.error("ERROR ", x),
valid: x => console.log(x)
};
// runtime
validateProfile({
user: { name: "jao", team: "A" },
color: "red"
}).cata(printValidation);
validateProfile({
user: { name: "jao", team: 1 },
color: "red"
}).cata(printValidation);
validateProfile({
color: "red"
}).cata(printValidation);
validateProfile(null)
.cata(printValidation);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment