[Haskell-cafe] Type Families
Dan Doel
dan.doel at gmail.com
Sun Sep 20 22:16:58 EDT 2009
On Sunday 20 September 2009 9:43:53 pm Alexander Solla wrote:
> But I more-or-less expected that to fail. I realize I need some more
> typing information. What am I supposed to fill in? My next guess was
>
> > value (SumValue (Sum a b)) = (value $ Value a) + (value $ Value
>
> b)
>
> But Value doesn't exist as a type constructor. So now that I am
> starting to "get" what's going on, I wonder why I don't get what's
> going on. Since I need to use a type constructor for the (Value a)
> and (Value b) "things", it kind of defeats the point. (I hesitate to
> say "value", since I have been using "value" to mean the result/blah
> of an Evaluate instance)
Well, the obvious answer is that you should instead write
data Value (Add a b) = SumValue (Sum (Value a) (Value b))
So that they are already Values, and value can be called on them. I don't
really understand what you're using the data families for, though. Value looks
like sort of an identity wrapper around its argument.
> Speaking of which, I am still not sure what the difference between
> associate data type families and associated type constructor families
> are. The former use the data keyword in class declarations, and the
> latter use type keywords. What can I do with one and not the other?
Type families (as far as their use in classes goes) are for when the
associated type already exists. For instance, in a collection class:
class Collection c where
type Elem c :: *
...
You'll have instances:
instance Collection [a] where
type Elem [a] = a
...
By contrast, data families are for when you want to define new data types
indexed by the type. For instance, if you're doing generalized tries:
class Key k where
data Trie k :: * -> *
...
Then:
instance (Key k) => Key [k] where
data Trie [k] a = ListTrie (Maybe a) (Trie k (Trie [k] a))
...
You can, of course, approximate one with the other. If you use a data family,
you can use newtypes so there's no additional overhead (but you'll have to
sprinkle constructors in your code). And data families can be simulated like
(using the Trie example):
class Key k where
type Trie k :: * -> *
...
data ListTrie k a = ListTrie (Maybe a) (Trie k (ListTrie k a))
instance Key k => Key [k] where
type Trie [k] = ListTrie k
...
But in cases where you're writing lots of new data/newtype declarations, just
to refer to them with an associated type, you may was well use associated data
instead and remove the middle man. Of course, sometimes you may not be clearly
in either situation, so it may be a judgment call.
Type families are also useful if you want to do computation at the type level.
In that sense, type families are like (value-level) functions, and data
families are like (value-level) constructors (I think that's accurate).
Hope that helped a bit,
-- Dan
More information about the Haskell-Cafe
mailing list