Please review these string checking functions. This is the whole module
which is actually written here. It supports buffer
, array
, and
string
by checking the char
code.
const charCode = chr => typeof chr === 'number' ? chr : chr.charCodeAt(0)
const every = (fn) => (list) => {
for (let i = 0; i < list.length; ++i)
if (!fn(list[i])) return false
return true
}
const compose = (f, g) => a => f(g(a))
const inBetween = (num, min, max) => num >= min && num <= max
const space = code => code == 9 || code == 10 || code == 12 ||
code == 13 || code == 32
const numeric = code => inBetween(code, 48, 57)
const lowerAlpha = code => inBetween(code, 97, 122)
const upperAlpha = code => inBetween(code, 65, 90)
const alpha = code => lowerAlpha(code) || upperAlpha(code)
const alphaNumeric = code => numeric(code) || alpha(code)
const printable = code => space(code) || inBetween(code, 32, 127)
My thought is is that this style is less readable than the original one. What do you think about its readability? And do these functions satisfy what said as functional?
1 Answer 1
I think these are rather readable, actually more so than the original ones. You've condensed the functions considerably!
Going pointfree
One further possibility would be to go more "pointfree", which you find a lot of in Haskell, for example. Define or
in terms of functions (so its arguments can be evaluated lazily), then you can work at a higher level of abstraction:
const or = (f, g) => (...args) => f.apply(f, args) || g.apply(g, args)
const alpha = or(lowerAlpha, upperAlpha)
const alphaNumeric = or(numeric, alpha)
const printable = or(space, inBetween(32, 127))
And then you can configure inBetween
to accept the variable parameter separately:
const inBetween = (a, b) => x => a <= x && x <= b
const space = x => [9, 10, 12, 13, 32].includes(x)
const numeric = inBetween(48, 57)
const lowerAlpha = inBetween(97, 122)
const upperAlpha = inBetween(65, 90)
I find this a bit more readable, since it removes the repetition of the parameter code
. The resulting code is denser and reads nicely: "alpha means either lowerAlpha or upperAlpha", etc.
But really this comes down to your preferences. As far as
do these functions satisfy what said as functional?
that depends on your definitions/requirements. I'd say they're certainly functional in the sense of avoiding mutability, except for every
, and in the philosophy of composing together small functions.
every
A more functional every
might recurse while fn(x) is truthy and elements remain in the list, something like this:
const every = (pred, [head, ...tail]) =>
pred(head) && (tail.length ? every(pred, tail) : true)
but this won't behave nicely in current JS engines. One modification you could do now, though, is to use for...of
in every
, so that it also works on Sets, ES7 generators, and other iterables that might not be indexable:
const every = pred => list => {
for (let x of list) {
if (!pred(x)) return false
}
return true
}
Explore related questions
See similar questions with these tags.