Open byorgey opened 5 years ago
Really this isn't about constructors in particular but pattern synonyms in general. But I think we want to only allow simple bidirectional pattern synonyms, and "constructor" is still a good name for such things. Here's a general outline of a design:
constructor
before a type declaration, parse it as a normal type declaration but store a flag denoting that it is a constructor.termToPattern
function to allow application, as long as the thing on the left is a constructor. Also, when encountering a variable, we must check to see if it is a constructor name in scope to decide whether to turn it into a constructor pattern or a normal PVar
pattern.I was thinking that it would be nice to implement this so we can e.g. implement Bool
in a library, instead of having it built in. e.g.
type Bool = Unit + Unit
constructor false : Bool
false = inl(unit)
constructor true : Bool
true = inr(unit)
However, the big problem is that we want Bool
values to also be pretty-printed as false
and true
. This is a bit more complicated, but perhaps it's possible. The idea would be that for a given type, we classify ahead of time the possible values of that type and how they map onto the different possible constructors.
I have thought more about the above comment and am now convinced that it is possible in a principled way:
All of this would become much easier once Disco is eager and we don't have to interleave pretty-printing and evaluation. Note applications of delay
will just be pretty-printed as ...
or something like that; pretty-printing will not force evaluation at all.
Note that implementing Bool
in a library also requires #136 .
Note that case expressions {? ... ?}
are built-in notation that rely on Bool
. However, if Bool
was not built-in, I think we could do something similar to what e.g. Coq does (if I remember correctly): expressions are considered "truthy" or "falsy" simply depending on whether they use a left
or right
constructor.
Ultimately, though, I'm not sure it's worth it to have Bool
defined in a library.
Reading this over again, I think we definitely don't want Bool defined in a library. This whole issue is pretty low-priority but could be a fun issue for a student or other new contributor to tackle.
Currently we can define ADTs using recursive sum types, e.g.
We can then define constructor synonyms like
but these can only be used to construct
Tree
values, not to destruct them. i.e. when pattern matching on aTree
value we have to match onleft
/right
; we can't match onleaf
/node
. It would be cool to be able to specify thatleaf
andnode
are constructors, and have the system check that their definitions are also valid patterns. This shouldn't be too hard now that we actually process patterns as special terms anyway. So something likeThis is not a high priority, and pedagogically one might not want to introduce this feature, but it would be cool anyway and probably (?) not too hard to implement.