Reputation: 53826
Is every class not a type in Haskell :
Prelude> :t max
max :: Ord a => a -> a -> a
Prelude> :t Ord
<interactive>:1:1: Not in scope: data constructor ‘Ord’
Prelude>
Why does this not print Ord
type signature ?
Upvotes: 8
Views: 12902
Reputation: 60463
Ord
is not a type, but a typeclass. It does not have a type, but a kind:
Prelude> :k Ord
Ord :: * -> Constraint
Typeclasses are one of the wonderful things about Haskell. Check 'em out :-)
Upvotes: 3
Reputation: 71485
Okay, there's a couple of things going on here.
First when you write :t Ord
you're looking for something called Ord
in the value namespace; specifically it would have to be a constructor, since the name starts with a capital letter.
Haskell keeps types and values completely separate; there is no relationship between the name of a type and the names of a type's constructors. Often when there's only one constructor, people will use the same name as the type. An example being data Foo = Foo Int
. This declares two new named entities: the type Foo
and the constructor Foo :: Int -> Foo
.
It's not really a good idea to think of it as just making a type Foo
that can be used both in type expressions and to construct Foo
s. Because also common are declarations like data Maybe a = Nothing | Just a
. Here there are 2 different constructors for Maybe a
, and Maybe
isn't a name of anything at all at the value level.
So just because you've seen Ord
in a type expression doesn't mean that there is a name Ord
at the value level for you to ask the type of with :t
. Even if there were, it wouldn't necessarily be related top the type-level name Ord
.
The second point that needs clarifying is that no, classes are not in fact types. A class is a set of types (which all support the interface defined in the class), but it is not a type itself.
In vanilla Haskell type classes are just "extra" things. You can declare them with a class
declaration, instantiate them with an instance
declaration, and use them in special syntax attached to types (the stuff left of the =>
arrow) as constraints on type variables. But they don't really interact with the rest of the language, and you cannot use them in the main part of a type signature (the stuff right of the `=> arrow).
However, with the ConstraintKinds
extension on, type classes do become ordinary things that exist in the type namespace, just like Maybe
. They are still not types in the sense that there can never be any values that have them as types, so you can't use Ord
or Ord Int
as an argument or return type in a function, or have a [Ord a]
or anything like that.
In that they are a bit like type constructors like Maybe
. Maybe
is a name bound in the type namespace, but it is not a type as such; there are no values whose type is just Maybe
, but Maybe
can be used as part of an expression defining a type, as in Maybe Int
.
If you're not familiar with kinds, probably ignore everything I've said from ConstraintKinds
onwards; you'll probably learn about kinds eventually, but they're not a feature you need to know much about as a beginner. If you are, however, what ConstraintKinds
does is make a special kind Constraint
and have type class constraints (left of the =>
arrow) just be ordinary type-level things of kind Constraint
instead of special purpose syntax. This means that Ord
is a type-level thing, and we can ask it's kind with the :k
command in GHCI:
Prelude> :k Ord
* -> Constraint
Which makes sense; max
had type Ord a => a -> a -> a
, so Ord a
must have kind Constraint
. If Ord
can be applied to an ordinary type to yield a constraint, it must have kind * -> Constraint
.
Upvotes: 13
Reputation: 32309
Not quite. You can impose type constraints, so Ord a => a
is a type, but Ord a
isn't. Ord a => a
means "any type a
with the constraint that it is an instance of Ord
".
The error is because :t
expects an expression. When GHCi tries to interpret Ord
as an expression, the closest it can get to is a data constructor, since these are the only functions in Haskell that can start with capital letters.
Upvotes: 1
Reputation: 7707
Ord
isn't a type; it's a typeclass. Typeclasses allow you to associate supported operations with a given type (somewhat similar to interfaces in Java or protocols in Objective-C). A type (e.g. Int
) being an "instance" of a typeclass (e.g. Ord
) means that the type supports the functions of the Ord
typeclass (e.g. compare
, <
, >
etc.).
You can get most info about a typeclass using :i
in ghci, which shows you the functions associated with the typeclass and which types are instances of it:
ghci > :i Ord
class Eq a => Ord a where
compare :: a -> a -> Ordering
(<) :: a -> a -> Bool
(>=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(<=) :: a -> a -> Bool
max :: a -> a -> a
min :: a -> a -> a
-- Defined in ‘GHC.Classes’
instance Ord a => Ord (Maybe a) -- Defined in ‘Data.Maybe’
instance (Ord a, Ord b) => Ord (Either a b)
-- Defined in ‘Data.Either’
instance Ord Integer -- Defined in ‘integer-gmp:GHC.Integer.Type’
instance Ord a => Ord [a] -- Defined in ‘GHC.Classes’
...
Upvotes: 8