first commit
This commit is contained in:
commit
13c1ed7b2a
35 changed files with 3330 additions and 0 deletions
103
content/chapter2/_index.md
Normal file
103
content/chapter2/_index.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
+++
|
||||
title = "Types"
|
||||
weight = 2
|
||||
sort_by = "weight"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
|
||||
Every value expression and, in particular, every value identifier in BH
|
||||
has a *type*. In some cases the programmer must supply a *type
|
||||
signature* specifying this and in many cases the compiler infers it
|
||||
automatically. The BH programmer should be aware of types at all times.
|
||||
|
||||
```
|
||||
type ::= btype [ "->" type ]
|
||||
btype ::= [ btype ] atype
|
||||
atype ::= tycon | tyvar | ( { type , } )
|
||||
tycon ::= conId
|
||||
```
|
||||
|
||||
|
||||
Most type expressions have the form: *TypeConstructor* $t_1$ $\cdots$
|
||||
$t_n$ where $t_1$ $\cdots$ $t_n$ are themselves type expressions, and $n
|
||||
{\geq} 0$. The $t_1$ $\cdots$ $t_n$ are referred to as the *type
|
||||
arguments* to the type constructor. $n$ is also called the *arity* of
|
||||
the type constructor.
|
||||
|
||||
|
||||
Familiar basic types have zero-arity type constructors (no type
|
||||
arguments, $n = 0$). Examples:
|
||||
|
||||
- `Integer`
|
||||
- `Bool`
|
||||
- `String`
|
||||
- `Action`
|
||||
|
||||
Other type constructors have arity $n > 0$; these are also known as
|
||||
*parameterized types*.
|
||||
|
||||
Examples:
|
||||
|
||||
- `List Bool`
|
||||
- `List (List Bool)`
|
||||
- `Array Integer String`
|
||||
- `Maybe Integer`
|
||||
|
||||
These represent the types of lists of
|
||||
Booleans, lists of lists of Booleans, arrays indexed by integers and
|
||||
containing strings, and an optional result possibly containing an
|
||||
integer.
|
||||
|
||||
|
||||
A type can be *polymorphic*, indicated using type variables. Examples:
|
||||
|
||||
- `List a`
|
||||
- `List (Llist b)`
|
||||
- `Array i (List String)`
|
||||
|
||||
|
||||
These represent lists of things of some unknown type "`a`", lists of
|
||||
lists of things of some unknown type "`b`", and arrays indexed by some
|
||||
unknown type "`i`" and containing lists of strings.
|
||||
|
||||
|
||||
One type constructor is given special status in the syntax. The type of
|
||||
functions from arguments of type $t_1$ to results of type $t_2$ could
|
||||
have been written as:
|
||||
|
||||
Function $t_1$ $t_2$
|
||||
|
||||
but in BH we write the constructor as an infix arrow:
|
||||
|
||||
$t_1$ -\> $t_2$
|
||||
|
||||
These associate to the right, *i.e.,*
|
||||
|
||||
$t_1$ -\> $\cdots$ -\> $t_{n-1}$ -\> $t_n$ $\equiv$ $t_1$
|
||||
-\> ($\cdots$ -\> ($t_{n-1}$ -\> $t_n$))
|
||||
|
||||
|
||||
There is one particular set of niladic type constructors that look like
|
||||
numbers. These are used to represent certain "sizes". For example, the
|
||||
type:
|
||||
|
||||
`Bit 16`
|
||||
|
||||
consists of the unary type constructor `Bit` applied to type represented
|
||||
by the niladic type constructor "`16`". The type as a whole represents
|
||||
bit vectors of length 16 bits. Similarly the type
|
||||
|
||||
`UInt 32`
|
||||
|
||||
|
||||
represents the type of unsigned integers that can be represented in 32
|
||||
bits. These numeric types are said to have kind `#`, rather than kind
|
||||
`*` for value types.
|
||||
|
||||
|
||||
Strings can also be used as type, having kind `$`. This is less common,
|
||||
but string types are quite useful in the generics library, described in
|
||||
the *Libraries Reference Guide*. Examples:
|
||||
|
||||
- `MetaData#("Prelude","Maybe",PrimUnit,2)`
|
||||
- `MetaConsNamed#("Valid",1,1)`
|
108
content/chapter2/page1.md
Normal file
108
content/chapter2/page1.md
Normal file
|
@ -0,0 +1,108 @@
|
|||
+++
|
||||
title = "Type classes and overloading"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
BH's `class` and `instance` mechanisms form a systematic way to do
|
||||
*overloading* (the approach has been well tested in Haskell).
|
||||
|
||||
|
||||
Overloading is a way to use a common name to refer to a set of
|
||||
operations at different types. For example, we may want to use the "`<`"
|
||||
operator name for the integer comparison operation, the floating-point
|
||||
comparison operation, the vector comparison operation and the matrix
|
||||
comparison operation. Note that this is not the same as polymorphism: a
|
||||
polymorphic function is a *single* function that is meaningful at an
|
||||
infinity of types (*i.e.,* at every possible instantiation of the type
|
||||
variables in its type). An overloaded identifier, on the other hand,
|
||||
usually uses a common name to refer to a (usually) small set of distinct
|
||||
operations.
|
||||
|
||||
|
||||
Further, it may make sense to have "`<=`", "`>`" and "`>=`" operations
|
||||
wherever there is a "`<`" operation, on integers, floating points
|
||||
numbers, vectors and matrices. Rather than handle these separately, we
|
||||
say:
|
||||
|
||||
|
||||
- there is class of types which we will call `Ord` (for "ordered types"),
|
||||
- that the integer, floating point, vector and matrix types are members
|
||||
(or "instances") of this class, and
|
||||
- that all types that are members of this class have appropriate
|
||||
definitions for the "`<`", "`<=`", "`>`" and "`>=`" operations. We also
|
||||
say that these operations are *overloaded* across these instance types,
|
||||
and we refer to these operations as the *methods* of this class.
|
||||
|
||||
|
||||
Another example: we could use a class `Hashable` with an operation
|
||||
called `hash` to represent those types $T$ for which we can and do
|
||||
define a hashing function. Each such type $T$ has to specify how to
|
||||
compute the `hash` function at that type.
|
||||
|
||||
|
||||
Classes, and the membership of a type in a class, do not come into
|
||||
existence by magic. Every class is created explicitly using a class
|
||||
declaration, described in section
|
||||
[4.5](fixme).
|
||||
A type must explicitly be made an instance of a class and the
|
||||
corresponding class methods have to be provided explicitly; this is
|
||||
described in [4.6](fixme).
|
||||
|
||||
|
||||
### Context-qualified types
|
||||
|
||||
|
||||
Consider the following type declaration:
|
||||
|
||||
```hs
|
||||
sort :: (Ord a) => List a -> List a
|
||||
```
|
||||
|
||||
|
||||
It expresses the idea that a sorting function takes an (unsorted) input
|
||||
list of items and produces a (sorted) output list of items, but it is
|
||||
only meaningful for those types of items ("`a`") for which the ordering
|
||||
functions (such as "`<`") are defined. Thus, it is ok to apply `sort` to
|
||||
lists of `Integer`'s or lists of `Bool`'s, because those types are
|
||||
instances of `Ord`, but it is not ok to apply `sort` to a list of, say,
|
||||
`Counter`'s (assuming `Counter` is not an instance of the `Ord` class).
|
||||
|
||||
|
||||
In the type of `sort` above, the part before "`=>`" is called a
|
||||
*context*. A context expresses constraints on one or more type
|
||||
variables--- in the above example, the constraint is that any actual
|
||||
type "`a`" must be an instance of the `Ord` class.
|
||||
|
||||
|
||||
A context-qualified type has the following grammar:
|
||||
|
||||
```
|
||||
ctxType ::= [ context => ] type
|
||||
context ::= ( {classId { varId }, })
|
||||
classId ::= conId
|
||||
```
|
||||
|
||||
In the above example, the class `Ord` had only one type parameter
|
||||
(*i.e.,* it constrains a single type) but, in general, a type class can
|
||||
have multiple type parameters. For example, in BH we frequently use the
|
||||
class "`Bits a n`" which constrains the type represented by `a` to be
|
||||
representable in bit strings of length represented by the type `n`.
|
||||
|
||||
|
||||
> **NOTE:**
|
||||
>
|
||||
> When using an overloaded identifier `x` there is always a question of
|
||||
> whether or not there is enough type information available to the
|
||||
> compiler to determine which of the overloaded `x`'s you mean. For
|
||||
> example, if `read` is an overloaded function that takes strings to
|
||||
> integers or Booleans, and `show` is an overloaded function that takes
|
||||
> integers or Booleans to strings, then the expression `show (read s)` is
|
||||
> ambiguous--- is the thing to be read an integer or a Boolean?
|
||||
>
|
||||
> In such ambiguous situations, the compiler will so notify you, and you
|
||||
> may need to give it a little help by inserting an explicit type
|
||||
> signature, e.g.,
|
||||
>
|
||||
> ```hs
|
||||
> show ((read s) :: Bool)
|
||||
> ```
|
Loading…
Add table
Add a link
Reference in a new issue