Patrick Browne <patrick.browne <at> dit.ie> wrote:
> Thanks for all the very useful feed back on this thread.
> I would like to present my possibly incorrect summarized view:
> Class signatures can contain placeholders for constructors.
> These place-holder-constructors cannot be used in the class to define
> functions (I assume other in-scope constructors can be used). In the
> instance a real constructor can be substituted for the
> place-holder-constructor. Does this restrict the type of equation
> that can be used in a type class? It seems that some equations
> respecting the constructor discipline are not allowed.
Your intuition seems to be near the truth, although your terminology is
currently wrong. Let's look at an example:
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
The 'f' in the class header is probably what you call a "placeholder for
constructors". This is not a placeholder, but a type variable. It
represents a type. Incidentally in this case it indeed represents a
constructor, namely a /type/ constructor (like Maybe). This is an
important distinction, because generally when we talk about
"constructors", we mean /value/ constructors (like Just or Nothing):
data Maybe a = Just a | Nothing
Here Maybe is a type constructor. This is because it's not a type in
its own right, but is applied to another type (like Int) to yield an
actual type (Maybe Int). The type Maybe is applied to is represented
by the type variable 'a' in the code above. To simplify communication
we often call Maybe itself also a type, but it's really not.
Let's write the Functor instance for Maybe. It is common to use a
helper function (a so-called fold function), which allows us to express
many operations more easily. It's called 'maybe' for Maybe:
maybe :: b -> (a -> b) -> Maybe a -> b
maybe n j (Just x) = j x
maybe n j Nothing = n
instance Functor Maybe where
fmap f = maybe Nothing (Just . f)
This is the instance for Maybe. The type variable 'f' from the class
now becomes a concrete type constructor Maybe. In this instance you
have f = Maybe, so the type of 'fmap' for this particular instance
fmap :: (a -> b) -> (Maybe a -> Maybe b)
The notable thing here is that this is really not a
placeholder/replacement concept, but much more like a function and
application concept. There is nothing that stops you from having type
variables in an instance:
instance Functor (Reader e) where
As you can see there is still what you called a "placeholder" in this
instance, so the placeholder concept doesn't really make sense here.
The declaration can be read as:
"For every type 'e' the type 'Reader e' is an instance of the
Functor type class."
> I appreciate that in Haskell the most equations occur in the
> instances, [...]
Not at all. When programming Haskell you write lots and lots of
equations outside of class instances. Whenever you write "=" you
introduce an equation, for example in top-level definitions and in 'let'
and 'where' bindings.
> [...] but from my earlier post: "I merely wish to identify the
> strengths and weakness of *current Haskell type classes* as a pure
> *unit of specification*"
I think you will be interested in this Stack Overflow answer:
Even though the actual question answered is different, it does give a
nice overview of the strengths and weaknesses of type classes.
Not to be or to be and (not to be or to be and (not to be or to be and
(not to be or to be and ... that is the list monad.