-
-
Save deepakshrma/8edd876dc7e5593587d7ee4e877959cc to your computer and use it in GitHub Desktop.
const fill = function* (start = 0, end = 100, filter = (_) => true, mapper = (x) => x) { | |
while (start < end) { | |
if (filter(start)) | |
yield start; | |
mapper(start++); | |
} | |
}; | |
const isEven = (num) => num % 2 === 0; | |
const isOdd = (num) => num % 2 !== 0; | |
const evens = [...fill(0, 100, isEven)]; | |
const odds = [...fill(0, 100, isOdd)]; | |
const evensSquares = [...fill(0, 100, isEven, (x) => x * x)]; | |
console.log(evens); //[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98] | |
console.log(odds); //[1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99] | |
console.log(evensSquares); //[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98] | |
const fillNaturalNumbers = (start, end) => fill(start, end + 1); | |
const naturals = [...fillNaturalNumbers(1, 100)]; | |
console.log(naturals);//[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100] |
/** | |
* Original author @christiantakle | |
*/ | |
const identity = <A>(a: A) => a; | |
const constTrue = <A>(a: A) => true; | |
interface FillInput<A> { | |
range: [start: number, end: number]; | |
filter: (a: number) => boolean; | |
mapper: (a: number) => A; | |
} | |
function* fill<A>({ | |
range: [start, end], | |
filter = constTrue, | |
mapper, | |
}: FillInput<A>): Generator<A, void, undefined> { | |
while (start < end) { | |
if (filter(start)) yield mapper(start); | |
start++; | |
} | |
} | |
const isEven = (num: number) => num % 2 === 0; | |
const isOdd = (num: number) => num % 2 !== 0; | |
const evens = [ | |
...fill({ | |
range: [1, 101], | |
filter: isEven, | |
mapper: identity, | |
}), | |
]; | |
console.log(evens); | |
console.log([ | |
...fill({ | |
range: [1, 101], | |
filter: isEven, | |
mapper: (x) => x * x, | |
}), | |
]); |
@christiantakle , Thanks But comment seems un-relevant to the code.
- If you need to print natural numbers, u can write curry. Given sample works like array fill
Array(n).fill(1)
const fillNaturalNumbers = (start: number, end: number) => fill(start, end + 1)
const naturals = [...fillNaturalNumbers(1, 100)];
- filter is default version, no used of index. The default filter will always true.
- This code is not meant for typescript, Typescript version can be written as below
const fill = (start = 0,
end = 100,
filter = (_: number) => true,
mapper: (index: number) => any = (x) => x) => {
return {
[Symbol.iterator]: function* () {
while (start < end) {
if (filter(start)) yield start;
mapper(start++);
}
},
};
};
@christiantakle and your code is buggy:(1,100) includes 101....
function* fill(start = 0, end = 100, filter = (x) => true, mapper = (x) => x) {
while (start++ <= end) {
if (filter(start)) yield mapper(start);
}
}
console.log(JSON.stringify([...fill()]));// [1,2,3,4,5,6,7,8,9,10,11,12,13,
//14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83
//,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101]
@deepakshrma haha yeah I was writing in my editor and didn't copy the final code. Its indeed a bug its due to
while (start++ <= end) {
// should be
while (start++ < end) {
And great job catching things this its the thing that happening from writing and not running.
You can see my output is correct but the code is wrong.
@christiantakle : haha! no worries.. Reviews make code better ;)
Regards to:
https://gist.github.com/deepakshrma/8edd876dc7e5593587d7ee4e877959cc#gistcomment-3929109
- If you need to print natural numbers, u can write curry. Given sample works like array fill Array(n).fill(1)
Yes you are correct. It would better to just update the range input to your function rather than reimplement. Only saw it because the output was different from the author.
Sidenote:
I think that is partial function application and not currying. Most of the time the difference doesn't matter π
Simple example of a curried function.
const f = (x) => (y) => (z) => x + y + z
- filter is default version, no used of index. The default filter will always true.
I do understand what you mean and why you did it. Just seeing it because I write typescript and typed language most of the time so just mentioning for completeness.
And as you said it was never meant to be anything but javascript. I just think your code is a good basis to teach more things from.
Dumb example using a curried function to make a constTrue
function.
const constant = <A,B>(a:A) => (b:B) => A
const constTrue = constant(true)
Library in which both of the above exist
https://gcanti.github.io/fp-ts/modules/function.ts.html#consttrue
- This code is not meant for typescript, Typescript version can be written as below
Very nice! π
I would change its to an object argument since you cannot use that function with a mapper
and have the default filter
function
const constTrue = <A>(a: A) => true;
interface FillInput {
range: [start: number, end: number];
filter: (a: number) => boolean;
mapper?: (a: number) => number;
}
function* fill({
range: [start, end],
filter = constTrue,
mapper,
}: FillInput): Generator<number, void, undefined> {
while (start < end) {
if (filter(start)) yield mapper?.(start) ?? start;
start++;
}
}
const isEven = (num: number): boolean => num % 2 === 0;
const isOdd = (num: number): boolean => num % 2 !== 0;
const evens = [
...fill({
range: [1, 101],
filter: isEven,
}),
];
console.log(evens);
console.log([
...fill({
range: [1, 101],
filter: isEven,
mapper: (x) => x * x,
}),
]);
Hopefully I copy paste the correct code this time π
update
improved working in sidenote
update 2
Changed the typescript code to use the original range handling of @deepakshrma its more logical and update the range input to reflect the change.
update 3
removed generics doesn't work for mapper
update 4
add return type to fill
fn
Re-add generics but it forces you to provided a mapper
fn on every call
const identity = <A>(a: A) => a;
const constTrue = <A>(a: A) => true;
interface FillInput<A> {
range: [start: number, end: number];
filter: (a: number) => boolean;
mapper: (a: number) => A;
}
function* fill<A>({
range: [start, end],
filter = constTrue,
mapper,
}: FillInput<A>): Generator<A, void, undefined> {
while (start < end) {
if (filter(start)) yield mapper(start);
start++;
}
}
const isEven = (num: number): boolean => num % 2 === 0;
const isOdd = (num: number): boolean => num % 2 !== 0;
const evens = [
...fill({
range: [1, 101],
filter: isEven,
mapper: identity,
}),
];
console.log(evens);
console.log([
...fill({
range: [1, 101],
filter: isEven,
mapper: (x) => "changes the output type",
}),
]);
I tried something similar to write, However, the default to mapper still issue.
Type 'number' is not assignable to type 'A'.
If that could be solve.
@deepakshrma I've updated my first comment with information from our dialog. I removed the generics from the example where mapper
is optional you cannot typecheck it unless you use any
or unknown
neither which is ideal.
I've also added an example with generics but you have to supply a mapper
function to use it to make the type checker happy
context: https://www.linkedin.com/feed/update/urn:li:activity:6855002687952576512
range
input to reflect authors code.mapper
fn so its result isyield
ed instead of discardedfilter
default fn just to be explicit that it always take an argumentresults
update:
Failed to copy my final code to this gist see
https://gist.github.com/deepakshrma/8edd876dc7e5593587d7ee4e877959cc#gistcomment-3929111 and
https://gist.github.com/deepakshrma/8edd876dc7e5593587d7ee4e877959cc#gistcomment-3929113
update 2
Changed the code to use the original range handling of @deepakshrma its more logical and update the range input to reflect the change to match the authors output.
update 3
Changed the comment to reflect our dialog. If readers want to see typescript implementations you can see them here
(listed in chronological order)