Consider the following Abstract Data Type (using Haskell syntax):
data Expr = Literal String | Symbol String | And [Expr] | Or [Expr]
In Python, one can make use of dataclasses and inheritance to obtain a similar type construction:
@dataclass
class Expr:
# "union"
foo: str | None = None
bar: list["Expr"] | None = None
@dataclass
class Literal(Expr):
pass
@dataclass
class Symbol(Expr):
pass
@dataclass
class And(Expr):
pass
@dataclass
class Or(Expr):
pass
As an interesting exercise, I am wondering whether it is possible to obtain a similar effect, but with a different definition which avoids duplication. I came up with the following theoretical notation:
# simulate Haskell's
# data Expr = Literal String | Symbol String | And [Expr] | Or [Expr]
# the following will bring names into scope
(
make_adt(
type_cons="Expr",
possible_fields=[
("foo", str),
("bar", list["Expr"]),
],
)
.add_data_cons("Literal", fields=["foo"])
.add_data_cons("Symbol", fields=["foo"])
.add_data_cons("And", fields=["bar"])
.add_data_cons("Or", fields=["bar"])
)
Here I am saying that there's a base type (the Expr type constructor) with 4 data constructors: Literal, Symbol, And, Or.
Each data constructor takes an additional argument (either str or list[Expr]), which is referred in the fields argument above (must be a subset of the possible_fields).
So:
Literal("foo"): sets thefoofield for the instanceAnd([Literal("foo"), Symbol("baz")]): sets thebarfield for the instance
The constraint here, as opposed to plain inheritance, is that that Literal and Symbol don't have the bar field, and similarly, And, Or, don't have the foo field. Or, to relax this a bit, we at least have to enforce that only non-null attributes are the ones defined in the fields list above.
My questions are:
- Can something like this be implemented?
- I'm thinking along the lines of attrs and dynamic
classcreation usingtype(...).
- I'm thinking along the lines of attrs and dynamic
- How brittle it would be?
P.S. I know it does not necessarily make sense to over-engineer this, especially in a dynamically typed language like Python, but I consider it to be an interesting exercise nonetheless.