Enable array destructuring on variants
Closed this issue · 0 comments
mlhaufe commented
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;
},
};