
On Monday 06 August 2007 19:23, Rahul Kapoor wrote:
Most examples for defining algebraic types include data constructors like so:
data Tree a = Tip | Node a (Tree a) (Tree a)
I by mistake defined a type which did not specify a data constructor :
In this example, you have two different uses of the lexical name 'Term', and I think it is confusing you. One kind of use is as a data constructor; the other is as a type constructor. I've annotated the uses below:
data SearchCondition = Term Bool -- data constructor | SearchCondition :||: (Term Bool) -- type constructor
data Term a = Constant a -- defn of type constr 'Term'
sc :: SearchCondition sc = Term True -- data constructor
is ok, but
sc :: SearchCondition sc = Constant True
Now, here you have an expression of type 'Term Bool'. These can only appear on the right-hand side of :||: . This probably isn't what you want. Likely what you actually want is:
data SearchCondition = SearchTerm (Term Bool) | SearchCondition :||: (Term Bool)
Here, both uses of 'Term' refer to the type constructor.
is not (though this is what I intended to capture!).
So the question is what are types with no constructors good for? A simple example would be appreciated.
There are some situations where an explicitly empty type is useful. Type-level programming voodoo is one. Other times the void type is nice because it can be used as a parameter to a type constructor. For example, if you use the nested datatype representation of de Bruijn lambda terms [1], you can use the void type to create the type of closed terms (terms with no free variables). Here's the short version: data Void data Succ a = Zero | Incr a data Term a = Var a | App (Term a) (Term a) | Lam (Term (Succ a)) type ClosedTerm = Term Void [1] Richard Bird and Ross Patterson, _de Brujin Notation as a Nested Datatype_, Journal of Functional Programming 9(1):77-91, January 1999. Rob Dockins