A data type in Effes is basically what C would call a struct — a composition of values, each with a name. The data type itself has a name, which is strongly type-checked. Here's an example of the simplest data type possible, which is composed of zero values.
Okay, but not very interesting. How about something that can satisfy the a
Stack[A]assumption I introduced in the last post? A linked list node is a good place to start.
data Node[A] = head :: A, next :: (Nothing | Node[A])
This is similar to Haskell's
data, but with two key differences. First, the equivalent of record notation is required. You can't define a
data Node[A] (A, Nothing|Node[A]); each value must be named. Secondly, each data type has exactly one constructor. In Haskell, you can define a type as the union of multiple constructors:
data Maybe a = Nothing | Just a
In Effes, this appears as two completely separate types:
data Nothing () data One[A] = value :: A
In the previous post, I mentioned nicknames as a way to alias the conjunction or disjunction of assumptions. Let's provide a nickname for the union of
Node[A], and then show how this union satisfies the
nickname LinkedList[A] = Nothing | Node[A] LinkedList[A] -> Stack[A] st push a = Node(head = a, next = it) pop Nothing = Nothing pop Node = next head n = case n of Nothing -> Nothing n = head n
(Read that second line as "being a LinkedList implies being a Stack, such that...") Here's the first thing to notice: a type which either
Node[A]can work as a
Stack[A]; it doesn't have to be typed as the union
Nothing | Node[A]. This reflects the reliance of type composition (for lack of a better word?) in Effes. (This shameless plug for synergistic abilities makes Effes the perfect language for Enterprise 2.0!) In other words, having defined this implication about
LinkedList[A]we can now
The next thing to notice is that
headprovide different syntax to express the same concept: "do abc if the input is a foo, or xyz if it's a bar." I'm not sure if I'll keep this duality, though. I'm tempted to get rid of the first form, and require all matching to be done via
case. We'll see.
pophas a covariant return type. The
Stack[A]assumption knows only that
Stack[A], but the
LinkedList[A]nickname knows that its implementation of
pophas two code branches, one of which returns
Nothingand the other of which returns
Node[A]. This means that
Nothing | Node[A], which still satisfies the
Stack[A]requirement, but is more specific than it.
In the next few posts, I'll talk a bit about function resolution rules and stateful assumptions, which blur the line between data types and assumptions as I've discussed them so far. I'll then talk a bit more about the role of composition in Effes — more of the synergy 2.0 stuff. I tell ya, I'm a few XML docs away from an IPO with this, baby.