One of the first things to confuse me about Haskell was the number of keywords related to types. The five (I know, 5 isn’t that many) I’ve counted in Haskell 98 are
class. I was unable to find a comprehensive discussion of what each of them means and how they are related to each other. I’ll break these keywords up linto 2 related sets.
newtype are all ways to declare a new type.
class are slightly different. Let’s take a closer look at them.
data is used to declare a new algebraic data type. We can use it to create a boolean or, in this case, the maybe monad:
data Bool = True | False data Maybe a = Nothing | Just a
type is used to create an alias for an algebraic data type. A good example of this is included in the Prelude:
type String = [Char]
newtype acts similarly to
type with a syntax akin to
data. Thus we can write the following:
newtype Radius = Radius Double data Diameter = Diameter Double
Okay, so what’s the difference between newtype and data? Three things (that I’m aware of):
newtypecan only have a single constructor taking a single argument.
newtypecreates a strict value constructor and
typecreates a lazy one (see ).
newtypeintroduces no runtime overhead.
A typeclass is a way to guarantee that a type implements certain functions (or data). A type is declared to implement the functions using the keyword
instance. An example will be helpful:
--Normally I would use Double, but Int's will be easier to read type Point = (Int, Int) data Triangle = Triangle Point Point Point deriving (Show) data Square = Square Point Point Point Point deriving (Show) class Shape a where rotate :: a -> a simple :: a instance Shape Triangle where rotate (Triangle x y z) = Triangle z x y simple = Triangle (0, 0) (1, 0) (0, 1) instance Shape Square where rotate (Square w x y z) = Square z w x y simple = Square (0, 0) (1, 0) (1, 1) (0, 1)
As you can see, we first define 3 simple types. Next, the ”
class Shape ...” bit, that’s the typeclass definition. All we’re doing is telling the compiler what must be defined for an instance of
Shape. With the
instance keyword, we make our classes instances of
Shape by defining the necessary stuff (i.e. rotate and simple). Let’s try it in GHCi:
Prelude> :l shape.hs [1 of 1] Compiling Main. ( shape.hs, interpreted ) *Main> simple :: Square Square (0,0) (1,0) (1,1) (0,1) *Main> rotate it Square (0,1) (0,0) (1,0) (1,1) *Main> simple :: Triangle Triangle (0,0) (1,0) (0,1) *Main> rotate it Triangle (0,1) (0,0) (1,0) *Main> rotate it Triangle (1,0) (0,1) (0,0)
Shape, we know that we can call rotate on them. That’s all a typeclass does. I tend to think of them as an interface or a contract.
newtype are about making types.
class are about making typeclasses.
PS, there’s another keyword,
deriving, that could fit in this discussion. It seems less confusing to me, so I won’t cover it.