(() => {
"use strict";
// --- POSITIONS OF A GIVEN CHARACTER IN A STRING ----
// charPositions :: Char -> String -> [Int]
const charPositions = c =>
s => [...s].reduceRight(
(a, x, i) => c === x ? (
[1 + i, ...a]
) : a,
[]
);
// ---------------------- TEST -----------------------
const main = () => {
const
positions = charPositions("¥")(
"Blue¥green¥white¥purple¥black"
),
gaps = zipWith(a => b => b - a)(
[1, ...positions]
)(
positions
);
return {
positions,
gaps
};
};
// --------------------- GENERIC ---------------------
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = f =>
// A list constructed by zipping with a
// custom function, rather than with the
// default tuple constructor.
xs => ys => xs.map(
(x, i) => f(x)(ys[i])
).slice(
0, Math.min(xs.length, ys.length)
);
return JSON.stringify(main());
})();
PS – it's a matter of taste, but charPositions could also be written in terms of .flatMap (rather than .reduce or .reduceRight), and perhaps flatMap does need fewer moving parts:
// charPositions :: Char -> String -> [Int]
const charPositions = c =>
s => [...s].flatMap(
(x, i) => c === x ? (
[1 + i]
) : []
);
Expand disclosure triangle to view full .flatMap version
(() => {
"use strict";
// --- POSITIONS OF A GIVEN CHARACTER IN A STRING ----
// charPositions :: Char -> String -> [Int]
const charPositions = c =>
s => [...s].flatMap(
(x, i) => c === x ? (
[1 + i]
) : []
);
// ---------------------- TEST -----------------------
const main = () => {
const
positions = charPositions("¥")(
"Blue¥green¥white¥purple¥black"
),
gaps = zipWith(a => b => b - a)(
[1, ...positions]
)(
positions
);
return {
positions,
gaps
};
};
// --------------------- GENERIC ---------------------
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = f =>
// A list constructed by zipping with a
// custom function, rather than with the
// default tuple constructor.
xs => ys => xs.map(
(x, i) => f(x)(ys[i])
).slice(
0, Math.min(xs.length, ys.length)
);
return JSON.stringify(main());
})();
I've successfully used this part to set the position of the first § (in my original question I used the Yen char) and the position of the 3 remaining gaps.
Then I tried to use a variable instead of the fixed string:
But I must be doing something wrong here. Can you help me here?
Finally, I'd like to make number of gaps flexible, via a loop. Now I repeat the steps for the gaps (that rhymes) 3 times, but surely there must be a way to make this flexible.
(In my original example, you will see that JSON.stringify is applied at the last moment – wrapped around the call to main(), so that a JSON string version of the dictionary (containing the positions and gaps arrays) is returned to the rest of the macro)
Let's get that working, and then I may ask you more about your second question.
Probably a bit unrealistic to show code and ask what the problem is – syntax checking is never a good use of a human, there are editor plugins for that – you always need to describe what you expected, and what you saw, even if that is only an error message.
This is what we needed to see straight away, before even the code: