type Reducer<A, B> = (acc: B, val: A) => B;
type Transducer<A, B> = <C>(rf: Reducer<B, C>) => Reducer<A, C>;
const mapT = <A, B>(fn: (a: A) => B): Transducer<A, B> =>
(rf) => (acc, val) => rf(acc, fn(val));
const filterT = <A>(pred: (a: A) => boolean): Transducer<A, A> =>
(rf) => (acc, val) => pred(val) ? rf(acc, val) : acc;
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const isEven = (n: number) => n % 2 === 0;
const triple = (n: number) => n * 3;
const xform = (rf: Reducer<number, number[]>) =>
filterT(isEven)(mapT(triple)(rf));
const result = nums.reduce(
xform((acc, val) => [...acc, val]),
[] as number[]
);