Reputation: 1160
I have code like this:
A = [1,2,3]
if (condition) {A.push(4)}
A.push(5)
But my array is actually immutable so I can't do that. How can I do it all in one expression? I don't want a null value in the middle.
Upvotes: 0
Views: 99
Reputation: 74204
You can use the Writer
monad here.
// type Writer t a = { value :: a, array :: [t] }
// pure :: a -> Writer t a
const pure = (value) => ({ value, array: [] });
// bind :: (Writer t a, a -> Writer t b) -> Writer t b
const bind = (writerA, arrow) => {
const writerB = arrow(writerA.value);
const array = [...writerA.array, ...writerB.array];
return { value: writerB.value, array };
};
// tell :: [t] -> Writer t ()
const tell = (array) => ({ value: undefined, array });
const writer = (gen) => {
const next = (data) => {
const { value, done } = gen.next(data);
return done ? value : bind(value, next);
};
return next(undefined);
};
const example = (condition) => writer(function* () {
yield tell([1, 2, 3]);
if (condition) yield tell([4]);
return tell([5]);
}());
console.log(example(true).array); // [1,2,3,4,5]
console.log(example(false).array); // [1,2,3,5]
Upvotes: 1
Reputation: 1160
Here is one way:
A = [1, 2, 3, ...(condition ? [4] : []), 5]
If this is common in your codebase, and you want to keep undefined then you write a filter function with a sentinel.
const REMOVE = symbol('removeme')
const A = clean([1, 2, 3, condition ? 4 : REMOVE, 5])
function clean(arr) {return arr.filter(x=>x!==REMOVE)}
Upvotes: 1