The data
and type
keywords always confuse me.
I want to know what is the difference between data
and type
and how to use them.
The data
and type
keywords always confuse me.
I want to know what is the difference between data
and type
and how to use them.
type
works just likelet
: it allows you to give a re-usable name to something, but that something will always work just as if you had inlined the definition. Sobehaves exactly the same way as
as in: you can anywhere in your code replace
f
withf'
and vice versa; nothing would change.OTOH, both
data
andnewtype
create an opaque abstraction. They are more like a class constructor in OO: even though some value is implemented simply in terms of a single number, it doesn't necessarily behave like such a number. For instance,Here, although
Logscaledℝ
is data-wise still just aDouble
number, it clearly behaves different fromDouble
.type
declares a type synonym. A type synonym is a new name for an existing type. For example, this is howString
is defined in the standard library:String
is another name for a list ofChar
s. GHC will replace all usages ofString
in your program with[Char]
at compile-time.To be clear, a
String
literally is a list ofChar
s. It's just an alias. You can use all the standard list functions onString
values:data
declares a new data type, which, unlike a type synonym, is different from any other type. Data types have a number of constructors defining the possible cases of your type. For example, this is howBool
is defined in the standard library:A
Bool
value can be eitherTrue
orFalse
. Data types support pattern matching, allowing you to perform a runtime case-analysis on a value of a data type.data
types can have multiple constructors (as withBool
), can be parameterised by other types, can contain other types inside them, and can recursively refer to themselves. Here's a model of exceptions which demonstrates this; anError a
contains an error message of typea
, and possibly the error which caused it.It's important to realise that
data
declares a new type which is apart from any other type in the system. IfString
had been declared as adata
type containing a list ofChar
s (rather than a type synonym), you wouldn't be able to use any list functions on it.There's one more variety of type declaration:
newtype
. This works rather like adata
declaration - it introduces a new data type separate from any other type, and can be pattern matched - except you are restricted to a single constructor with a single field. In other words, anewtype
is adata
type which wraps up an existing type.The important difference is the cost of a
newtype
: the compiler promises that anewtype
is represented in the same way as the type it wraps. There's no runtime cost to packing or unpacking anewtype
. This makesnewtype
s useful for making administrative (rather than structural) distinctions between values.newtype
s interact well with type classes. For example, considerMonoid
, the class of types with a way to combine elements (mappend
) and a special 'empty' element (mempty
).Int
can be made into aMonoid
in many ways, including addition with 0 and multiplication with 1. How can we choose which one to use for a possibleMonoid
instance ofInt
? It's better not to express a preference, and usenewtype
s to enable either usage with no runtime cost. Paraphrasing the standard library:With
data
you create new datatype and declare a constructor for it:With
type
you define just an alias:In the
type
case you can pass value ofMyChar
type to function expecting aChar
and vice versa, but you can't do this fordata MyChar = MyChar Char
.