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?

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Aug 21, 2016 at 7:02
\$\endgroup\$
0

1 Answer 1

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
}
answered Aug 22, 2016 at 4:49
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.