News for hackers. Stuff that matters.
Re:The visitor pattern is essentially the same thing as Chur... by gampleman on Thursday February 04, 2021 @05:46AM (#26024317)
This is a valid definition in TypeScript:

    type Shape<T> = (
        circle: (x: number, y: number, r: number) => T,
        rectangle: (x: number, y: number, w: number, h: number) => T
    ) => T;

    function Circle<T>(x: number, y: number, r: number): Shape<T> {
        return (_Circle, _Rectangle) => _Circle(x, y, r);
    }

    function Rectangle<T>(x: number, y: number, w: number, h: number): Shape<T> {
        return (_Circle, _Rectangle) => _Rectangle(x, y, w, h);
    }

    const exampleCircle = Circle(2, 1.4, 4.5);
    const exampleRectangle = Rectangle(1.3, 3.1, 10.3, 7.7);

    function area(shape: Shape<unknown>): number {
        const s = shape as Shape<number>;
        return s(
            (x, y, r) => Math.PI * r * r,
            (x, y, w, h) => w * h
        );
    }

    export function main() {
        console.log(area(exampleCircle));
        console.log(area(exampleRectangle));
    }
Unfortunately I think the cast might be necessary, but happy to see another solution from someone with more typescript expertise.
Re:The visitor pattern is essentially the same thing as Chur... by lmm on Thursday February 04, 2021 @05:58AM (#26024370)
You just need to make the function generic rather than the type:

    type Shape = <T extends unknown>(
        circle: (x: number, y: number, r: number) => T,
        rectangle: (x: number, y: number, w: number, h: number) => T
    ) => T;

    function Circle<T>(x: number, y: number, r: number): Shape {
        return (_Circle, _Rectangle) => _Circle(x, y, r);
    }

    function Rectangle<T>(x: number, y: number, w: number, h: number): Shape {
        return (_Circle, _Rectangle) => _Rectangle(x, y, w, h);
    }

    const exampleCircle = Circle(2, 1.4, 4.5);
    const exampleRectangle = Rectangle(1.3, 3.1, 10.3, 7.7);

    function area(shape: Shape): number {
        return shape(
            (_x, _y, r) => Math.PI * r * r,
            (_x, _y, w, h) => w * h
        );
    }

    function main() {
        console.log(area(exampleCircle));
        console.log(area(exampleRectangle));
    }
    main()
Re:The visitor pattern is essentially the same thing as Chur... by monzee on Thursday February 04, 2021 @08:14AM (#26025038)
You can generalize this with TS's fancy mapped types:

    type Sum<K> = <T> (cases: Pattern<K, T>) => T
    type Pattern<K, T> = {
      [V in keyof K]: K[V] extends any[] ? (...args: K[V]) => T : never
    }
which takes TS very close to ML:

    type Shape = Sum<{
      circle: [number, number, number],
      rectangle: [number, number, number, number]
    }>

    function Circle(x: number, y: number, r: number): Shape {
      return ({ circle }) => circle(x, y, r);
    }

    function Rectangle(x: number, y: number, w: number, h: number): Shape {
      return ({ rectangle }) => rectangle(x, y, w, h);
    }

    function area(shape: Shape): number {
      return shape({
        circle: (x, y, r) => Math.PI * r * r,
        rectangle: (x, y, w, h) => w * h
      });
    }
Re:The visitor pattern is essentially the same thing as Chur... by DougBTX on Thursday February 04, 2021 @05:56AM (#26024365)
It works without the cast if Shape is a generic function itself:

    type Shape = <T>(
        circle: (x: number, y: number, r: number) => T,
        rectangle: (x: number, y: number, w: number, h: number) => T
    ) => T;

    function Circle(x: number, y: number, r: number): Shape {
        return (_Circle, _Rectangle) => _Circle(x, y, r);
    }

    function Rectangle(x: number, y: number, w: number, h: number): Shape {
        return (_Circle, _Rectangle) => _Rectangle(x, y, w, h);
    }

    const exampleCircle = Circle(2, 1.4, 4.5);
    const exampleRectangle = Rectangle(1.3, 3.1, 10.3, 7.7);

    function area(shape: Shape): number {
        return shape(
            (x, y, r) => Math.PI * r * r,
            (x, y, w, h) => w * h
        );
    }

    console.log(area(exampleCircle));
    console.log(area(exampleRectangle));
Re:The visitor pattern is essentially the same thing as Chur... by throw_m239339 on Thursday February 04, 2021 @06:19AM (#26024450)
I'm embarrassed to admit it took me a while to make sense of that code snippet.

Now, in order for it to work, a language has to support closures, not just functions.

Re:The visitor pattern is essentially the same thing as Chur... by Twisol on Thursday February 04, 2021 @06:34AM (#26024507)
> Now, in order for it to work, a language has to support closures, not just functions.

Objects are a reasonable stand-in for closures. Pass in the first batch of arguments to the constructor, and store them as fields. Access them from the method (which plays the role of the "returned" closure) when it's called later.

(This is effectively the same as "closure conversion" in the literature, but we're taking advantage of the implicit-receiver convention to hide the parameter by which we're passing the prepared fields.)

Re:The visitor pattern is essentially the same thing as Chur... by magicalhippo on Thursday February 04, 2021 @05:55AM (#26024356)
Thanks, that helps a lot!

Never used TypeScript either (I feel like such a Luddite these days) but this is perfectly understandable.