mlhaufe/brevity

Enable array destructuring on variants

Closed this issue · 0 comments

An array based implementation of polyArea with a lambda looks like this:

const polyArea = (vertices) => {
    if (vertices.length < 3)
        return 0
    const [v1, v2, v3, ...vs] = vertices,
        [, y1] = v1,
        [, y2] = v2,
        [, y3] = v3,
        widths = [distance(v1, v2), distance(v1, v3), distance(v2, v3)],
        heights = [avg(y1, y2), avg(y1, y3), avg(y2, y3)],
        trapezoidAreas = zip(widths, heights).map(([w, h]) => w * h);

    return sum(trapezoidAreas) + polyArea([v1, v3, ...vs]);
};

Converting to Trait on List:

const polyArea = Trait(List, {
    Nil: () => 0,
    Cons: [
        [Cons(_, Cons(_, Cons(_, _))), (self) => {
            const { head: v1, tail: { head: v2, tail: { head: v3, tail: vs } } } = self,
                y1 = v1.snd,
                y2 = v2.snd,
                y3 = v3.snd,
                widths = list(distance(v1, v2), distance(v1, v3), distance(v2, v3)),
                heights = list(avg(y1, y2), avg(y1, y3), avg(y2, y3)),
                trapezoidAreas = map(zip(widths, heights), ({ fst: w, snd: h }) => w * h);

            return sum(trapezoidAreas) + polyArea(vs);
        }],
        [_, () => 0]
    ]
})

The above is significantly more verbose than the lambda + array form.

Enabling positional destructuring on variants and a corresponding array pattern match on Trait the above can become:

const polyArea = Trait(List, {
    Nil: () => 0,
    Cons: [
        [[_, [_, [_, _]]], ([v1, [v2, [v3, vs]]]) => {
            [, y1] = v1,
            [, y2] = v2,
            [, y3] = v3,
            widths = list(distance(v1, v2), distance(v1, v3), distance(v2, v3)),
            heights = list(avg(y1, y2), avg(y1, y3), avg(y2, y3)),
            trapezoidAreas = map(zip(widths, heights), ([w, h]) => w * h);

            return sum(trapezoidAreas) + polyArea(vs);
        }],
        [_, () => 0]
    ]
})

The array pattern match though is too much of an ascii turd in this case. This could be replaced by using the list helper:

const polyArea = Trait(List, {
    Nil: () => 0,
    Cons: [
        [list(_, _, _), ([v1, [v2, [v3, vs]]]) => {
            [, y1] = v1,
            [, y2] = v2,
            [, y3] = v3,
            widths = list(distance(v1, v2), distance(v1, v3), distance(v2, v3)),
            heights = list(avg(y1, y2), avg(y1, y3), avg(y2, y3)),
            trapezoidAreas = map(zip(widths, heights), ([w, h]) => w * h);

            return sum(trapezoidAreas) + polyArea(vs);
        }],
        [_, () => 0]
    ]
})

It should be sufficient to implement Symbol.iterator on the prototype of every variant:

{
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  },
};