5
\$\begingroup\$

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?

\$\endgroup\$
2
\$\begingroup\$

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
}
|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.