Change `data` to no longer combine factory and variant declaration
Opened this issue · 3 comments
data
currently defines a class hierarchy as well as a factory for constructing instances of that hierarchy:
const colorData = data({ Red: {}, Green: {}, Blue: {} })
const PointData = data({
Point2: {x: Number, y: Number},
Point3: {x: Number, y: Number, z: Number}
})
const PeanoData = data(() => ({
Zero: {},
Succ: {pred: PeanoData}
}))
const ListData = data((T) => ({
Nil: {},
Cons: {head: T, tail: ListData(T) }
}))
This requires extra effort in type checking, complection, and declaration (due to the fixpoint requirement).
If data
did not declare a factory then the above forms can be represented as:
const ColorData = data({}),
Red = data(ColorData, {}),
Green = data(ColorData, {})
const PointData = data({}),
Point2 = data(PointData, {x: Number, y: Number}),
Point3 = data(PointData, {x: Number, y: Number})
const PeanoData = data({}),
Zero = data(PeanoData, {}),
Succ = data(PeanoData, {pred: PeanoData})
const ListData = (T) => {
const ListData = data({ of: T }),
Nil = data(ListData, {}),
Cons = data(ListData, { head: T, tail: ListData })
return List
}
The syntactic burden is comparable to the original forms except for the parameterized recursive form.
For complect
to work as desired, each data
declaration has a [children]
symbol that returns the extensions:
Peano[children] // [Zero, Succ]
Which enables:
const Peano = complect(PeanoData, [...])
This should have the added benefit of making type declarations easier as they are non-trivial in typescript and very challenging to express in jsdoc.
The parameterized recursive form will cause an issue with strict equality tests:
const NumListData1 = ListData(Number),
NumListData2 = ListData(Number)
NumListData1 !== NumListData2
const ListData = memofix((T) => {
const _ListData = data({ of: T }),
Nil = data(_ListData, {}),
Cons = data(_ListData, { head: T, tail: ListData(T) })
return _ListData
})
To derive a general solution I don't see how the splitting out of data
to one per class helps. The recursive form implies that an owning object needs to be returned. Add that to the requirement of a [children]
reference and it looks like we've come full-circle back to a factory-like object. abstracting the memofix form and generalizing for the family looks exactly like the original data
decl with a semantic distinction that doesn't seem to make much of a difference...
The Enumeration class pattern seems to be a reasonable counter-point: