[Haskell-cafe] difference between type and newtype
bulat.ziganshin at gmail.com
Sat Aug 26 10:00:02 EDT 2006
Saturday, August 26, 2006, 1:44:19 PM, you wrote:
>> perhaps this is silly, but it is not possible to declare function
>> could you please indicate me some documentation that explains this
>> kind of stuff? So far I didn't find anything on that.
> well, I've found something in the Report:
btw, i don't think that Report can be used to learn language, it's
better to look into various tutorials or, even better, textbooks
> 6.1.6 Function Types
> Functions are an abstract type: no constructors directly create
> functional values. The following simple functions are found in the
> Prelude: id, const, (.), flip, ($), and until.
> Now I'm trying to understand what "directly" stands for...
it's not something related to your question: Reports says here about
functional values, not types :)
i will try to make explanation you need.
first, Haskell has a few primitive datatypes - Char, Int, Bool...
second, it provides a way to construct new datatypes:
data T = C1 Int Char
| C2 Bool
here, T is new type whose values can be constructed _only_ using C1 or
C2 constructor. to be exact, we can construct value of type T, we can
either apply C2 to value of another type, Bool, f.e. "C2 True", or by
applying C1 to two values, Int and Char, f.e. C1 5 'a'
'newtype' declaration is equivalent to 'data', it just have some
'type' _don't_ constructs any new type, it just adds type _synonym_
with sole purpose to simplify using of complex type constructions
(it's just like 'typedef' in C if you know this language)
type String = [Char]
allows us to use String in function signatures instead of [Char]
Declarations of new types can have parameters:
data T a b = C1 a b
| C2 a
Such declaration effectively declares a _family_ of different types
what can be constructed by applying T2 type constructor to concrete
types, f.e. "T2 Int String", "T2 Int Int" or even "T2 (T2 Int Int) String"
In addition to predefined types (Int, Bool and so on) there are a
number of predefined type constructors. Some of them are defined in
data Either a b = Left a | Right b
data Maybe a = Just a | Nothing
data [a] = a : [a] | 
Last definition is a bit artificial, but modulo specific syntax, list
type constructor can be defined in Haskell proper:
data List a = Cons a (List a) | Nil
Function is among predefined type constructors, but it cannot be
defined using Haskell itself:
data (->) a b = ....
But in all other aspects, '->' can be seen as ordinal type constructor
which has two type parameters. This means that you don't need nor
can't to define _new_ functional types using 'data' definition. But
you can and should use type synonym declarations when you need to
"specialize" (->) type constructor, i.e. give name to some concrete
functional type, f.e.
type HashFunction = (String->Int)
This synonym can then be used in type specification like the right
part in its definition, i.e. declarations
createHash :: HashFunction -> IO Hash
createHash :: (String->Int) -> IO Hash
are equivalent. So, technically speaking, you can't declare function
types, there is only one predefined type constructor that can
construct any function type you need. But from practical POV, you can
define synonyms for any function type you've constructed using '->'.
If you want, you can also declare parametric type synonyms:
type HashFunction a = (a->Int)
or something like
type CPS a b = a -> Either a b
It should be obvious that using parametric synonyms don't differ from
using parameterless ones:
createHash :: HashFunction Char -> IO (Hash Char)
is translated into
createHash :: (Char->Int) -> IO (Hash Char)
Next point is that in Haskell functions are first-class values, i.e.
you can hold them in data structures, pass as parameters to other
functions and even return them as results. For example, the following
function accepts function of type String->Int->Int and returns
function of type (Int->Int):
func :: (String->Int->Int) -> (Int->Int)
func f = f ""
The following data type includes function as one of its fields:
data T = C (String->Int->Int) Int
As i already said, newtype is just limited form of 'data' declaration,
one which should use exactly one constructor with exactly one field,
newtype I = I Int
Such restrictions guarantee that new type defined may use the same
representation as its only field, and in fact newtype language
construct guarantees it. But it is only internal representation, from
the programmer's POV newtype is don't differs from 'data'
Of course, newtype can also be used to define type whose only field
contains some function:
newtype F = F (String->Int)
Again, in this case language guarantees that internal F representation
will be the same as for plain (Int->String) function and therefore the
same as for type synonym:
type S = String->Int
But from programmer POV, the difference still holds: while S denotes
function of given type and can be used interchangeably with full
notion of this function type, F is just the type which internally
contains such function. Values of type F can be constructed, as for
any other data type, only using F data constructor applied to function
of corresponding type, f.e. "F length". So, "F length" has type F
while 'length' itself may have type "String->Int" whose synonym is S
hope that it helps :)
Bulat mailto:Bulat.Ziganshin at gmail.com
More information about the Haskell-Cafe