first commit
This commit is contained in:
commit
13c1ed7b2a
35 changed files with 3330 additions and 0 deletions
12
content/chapter4/_index.md
Normal file
12
content/chapter4/_index.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
+++
|
||||
title = "Top Level Definitions"
|
||||
weight = 4
|
||||
sort_by = "weight"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
|
||||
# Top level definitions
|
||||
|
||||
|
||||
Top level definitions can be used only on the top level within a
|
||||
package.
|
146
content/chapter4/page1.md
Normal file
146
content/chapter4/page1.md
Normal file
|
@ -0,0 +1,146 @@
|
|||
+++
|
||||
title = "`data`"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
A `data` definition defines a brand new type, which is different from
|
||||
every primitive type and every other type defined using a `data`
|
||||
definition, even if they look structurally similar. The new type defined
|
||||
by a `data` definition is a "sum of products", or a "union of products".
|
||||
|
||||
```
|
||||
topDefn ::= data typeId {tyVarId } = {summand | }[ derive ]
|
||||
summand ::= conId {type }
|
||||
summand ::= conId { { fieldDef ; }}
|
||||
derive ::= deriving ( { classId , })
|
||||
fieldDef ::= fieldId :: type
|
||||
```
|
||||
|
||||
The *typeId* is the name of this new type. If the *tyVarId*'s exist,
|
||||
they are type parameters, thereby making this new type polymorphic. In
|
||||
each *summand*, the *conId* is called a "constructor". You can think of
|
||||
them as unique *tag*'s that identify each summand. Each *conId* is
|
||||
followed by a specification for the fields involved in that summand
|
||||
(*i.e.,* the fields are the "product" within the summand). In the first
|
||||
way of specifying a summand, the fields are just identified by position,
|
||||
hence we only specify the types of the fields. In the second way of
|
||||
specifying a summand, the fields are named, hence we specify the field
|
||||
names (*fieldId*'s) and their types.
|
||||
|
||||
|
||||
The same constructor name may occur in more than one type. The same
|
||||
field name can occur in more than one type. The same field name can
|
||||
occur in more than one summand within the same type, but the type of the
|
||||
field must be the same in each summand.
|
||||
|
||||
|
||||
The optional *derive* clause is used as a shorthand to make this new
|
||||
type an instance of the *classId*'s, instead of using a separate,
|
||||
full-blown `instance` declaration. This can only be done for certain
|
||||
predefined *classId*'s: `Bits`, `Eq`, and `Bounded`. The compiler
|
||||
automatically derives the operations corresponding to those classes
|
||||
(such as `pack` and `unpack` for the `Bits` class). Type classes,
|
||||
instances, and `deriving` are described in more detail in sections
|
||||
[2.1](fixme), [4.5](fixme) and [
|
||||
4.6](fixme).
|
||||
|
||||
To construct a value corresponding to some `data` definition $T$, one
|
||||
simply applies the constructor to the appropriate number of arguments
|
||||
(see section [5.3](fixme){reference-type="ref"
|
||||
reference="sec-exprs-constrs"}); the values of those arguments become
|
||||
the components/fields of the data structure.
|
||||
|
||||
|
||||
To extract a component/field from such a value, one uses pattern
|
||||
matching (see section [6](fixme){reference-type="ref"
|
||||
reference="sec-patterns"}).
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
data Bool = False | True
|
||||
```
|
||||
|
||||
|
||||
This is a "trivial" case of a `data` definition. The type is not
|
||||
polymorphic (no type parameters); there are two summands with
|
||||
constructors `False` and `True`, and neither constructor has any fields.
|
||||
It is a 2-way sum of empty products. A value of type `Bool` is either
|
||||
the value `False` or the value `True` Definitions like these correspond
|
||||
to an "enum" definition in C.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
data Operand = Register (Bit 5)
|
||||
| Literal (Bit 22)
|
||||
| Indexed (Bit 5) (Bit 5)
|
||||
```
|
||||
|
||||
|
||||
Here, the first two summands have one field each; the third has two
|
||||
fields. The fields are positional (no field names). The field of a
|
||||
`Register` value must have type Bit 5. A value of type `Operand` is
|
||||
either a `Register` containing a 5-bit value, or a `Literal` containing
|
||||
a 22-bit value, or an `Indexed` containing two 5-bit values.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
data Maybe a = Nothing | Just a
|
||||
deriving (Eq, Bits)
|
||||
```
|
||||
|
||||
This is a very useful and commonly used type. Consider a function that,
|
||||
given a key, looks up a table and returns some value associated with
|
||||
that key. Such a function can return either `Nothing`, if the table does
|
||||
not contain an entry for the given key, of `Just `$v$, if the table
|
||||
contains $v$ associated with the key. The type is polymorphic (type
|
||||
parameter "`a`") because it may be used with lookup functions for
|
||||
integer tables, string tables, IP address tables, etc., *i.e.,* we do
|
||||
not want here to over-specify the type of the value $v$ at which it may
|
||||
be used.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
data Instruction = Immediate { op::Op; rs::Reg; rt::CPUReg; imm::UInt16; }
|
||||
| Jump { op::Op; target::UInt26; }
|
||||
```
|
||||
|
||||
|
||||
An `Instruction` is either an `Immediate` or a `Jump`. In the former
|
||||
case, it contains a field called `op` containing a value of type `Op`, a
|
||||
field called `rs` containing a value of type `Reg`, a field called `rt`
|
||||
containing a value of type `CPUReg`, and a field called `imm` containing
|
||||
a value of type `UInt16`. In the latter case, it contains a field called
|
||||
`op` containing a value of type `Op`, and a field called `target`
|
||||
containing a value of type `UInt26`.
|
||||
|
||||
> **NOTE:**
|
||||
>
|
||||
> Error messages involving data type definitions sometimes show traces of
|
||||
> how they are handled internally. Data type definitions are translated
|
||||
> into a data type where each constructor has exactly one argument. The
|
||||
> types above translate to:
|
||||
>
|
||||
> ```hs
|
||||
> data Bool = False PrimUnit | True PrimUnit
|
||||
>
|
||||
> data Operand = Register (Bit 5)
|
||||
> | Literal (Bit 22)
|
||||
> | Indexed Operand_$Indexed
|
||||
> struct Operand_$Indexed = { _1 :: Reg 5; _2 :: Reg 5 }
|
||||
>
|
||||
> data Maybe a = Nothing PrimUnit | Just a
|
||||
>
|
||||
> data Instruction = Immediate Instruction_$Immediate
|
||||
> | Register Instruction_$Register
|
||||
>
|
||||
> struct Instruction_$Immediate = { op::Op; rs::Reg; rt::CPUReg; imm::UInt16; }
|
||||
> struct Instruction_$Register = { op::Op; target::UInt26; }
|
||||
> ```
|
68
content/chapter4/page2.md
Normal file
68
content/chapter4/page2.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
+++
|
||||
title = "`struct`"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
Defines a record type (a "pure product"). This is a specialized form of
|
||||
a `data` definition. The same field name may occur in more than one
|
||||
type.
|
||||
|
||||
```
|
||||
topDefn ::= struct typeId {tyVarId }= { { fieldDef ; }} [ derive ]
|
||||
fieldDef ::= fieldId :: type
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
struct Proc = { pc :: Addr; rf :: RegFile; mem :: Memory }
|
||||
struct Coord = { x :: Int; y :: Int }
|
||||
```
|
||||
|
||||
|
||||
Section [5.6](fixme) describes how to construct values of a
|
||||
`struct` type. A field of a `struct` type can be extracted either
|
||||
directly using "dot" notation (section
|
||||
[5.7](fixme)) or using pattern matching (section
|
||||
[6.3](fixme)).
|
||||
|
||||
|
||||
### Tuples {#sec-tuple-type}
|
||||
|
||||
|
||||
One way to group multiple values together is to use a `data` definition
|
||||
in which a constructor has multiple fields.
|
||||
|
||||
|
||||
However, there is a built-in notation for a common form of grouping,
|
||||
called "tuples". To group two (or more) values together the Prelude
|
||||
contains a type, `PrimPair`, for which there is syntactic sugar for type
|
||||
expressions, value expressions, and patterns.
|
||||
|
||||
The type has the following definition
|
||||
|
||||
```hs
|
||||
struct PrimPair a b = { fst :: a; snd :: b } deriving (Eq, Bits, Bounded)
|
||||
```
|
||||
|
||||
For type expressions the following shorthand can be used:
|
||||
|
||||
(a, b) $\equiv$ PrimPair a b
|
||||
|
||||
Or, more generally,
|
||||
|
||||
($t_1$, $t_2$, $\cdots$, $t_n$) $\equiv$ PrimPair $t_1$ (PrimPair $t_2$ ($\cdots$ $t_n$))
|
||||
|
||||
|
||||
There is a corresponding shorthand for value expressions and patterns:
|
||||
|
||||
(a, b) $\equiv$ PrimPair { fst = a; snd = b }
|
||||
|
||||
There is also special syntax for the empty tuple. It is written "`()`"
|
||||
for types, expressions, and patterns. The real type has the following
|
||||
definition
|
||||
|
||||
```hs
|
||||
struct PrimUnit = { } deriving (Eq, Bits, Bounded)
|
||||
```
|
||||
|
38
content/chapter4/page3.md
Normal file
38
content/chapter4/page3.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
+++
|
||||
title = "`type`"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
Defines a type synonym. These are used purely for readability, *i.e.,* a
|
||||
type synonym can always be "expanded out" to its definition at any time.
|
||||
|
||||
```
|
||||
topDefn ::= type typeId {tyVarId }= type
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```hs
|
||||
type Byte = Bit 8
|
||||
type Word = Bit 16
|
||||
type LongWord = Bit 32
|
||||
```
|
||||
|
||||
These provide commonly used names for certain bit lengths. In a
|
||||
specification of a processor:
|
||||
|
||||
```hs
|
||||
data RegName = R0 | R1 | ... | R31
|
||||
type Rdest = RegName
|
||||
type Rsrc = RegName
|
||||
data ArithInstr = Add Rdest Rsrc Rsrc
|
||||
| Sub Rdest Rsrc Rsrc
|
||||
```
|
||||
|
||||
the last two lines suggest the roles of the registers in the
|
||||
instructions, and is more readable than:
|
||||
|
||||
```hs
|
||||
data ArithInstr = Add RegName RegName RegName
|
||||
| Sub RegName RegName RegName
|
||||
```
|
43
content/chapter4/page4.md
Normal file
43
content/chapter4/page4.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
+++
|
||||
title = "`interface`"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
Defines an interface for a hardware module (see section
|
||||
[5.13](fixme)). An
|
||||
interface is essentially a `struct`, but its components are restricted
|
||||
to those things that have a physical interpretation as wires in and out
|
||||
of a circuit. The types of fields in an interface are more likely to
|
||||
involve `Action`'s (see section
|
||||
[5.11](fixme)),
|
||||
which are typically interpreted as "enable signals" into a circuit. The
|
||||
fields of an interface are also known as *methods* (not to be confused
|
||||
with methods of a class, described in Sections
|
||||
[2.1](fixme) and
|
||||
[4.5](fixme)).
|
||||
|
||||
```
|
||||
topDefn ::= interface typeId {tyVarId }= { { fieldDef ; }}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
interface Stack a =
|
||||
push :: a -> Action
|
||||
pop :: Action
|
||||
top :: Maybe a
|
||||
```
|
||||
|
||||
This describes a circuit that implements a stack (a LIFO) of items. This
|
||||
polymorphic definition does not specify the type of the contents of the
|
||||
stack, just that they have some type "`a`". Corresponding to the `push`
|
||||
method, the circuit will have input wires to carry a value of type
|
||||
"`a`", and a "push-enable" input wire that specifies when the value
|
||||
present on the input wires should be pushed on the stack. Corresponding
|
||||
to the `pop` component, the circuit will have a "pop-enable" input wire
|
||||
that specifies when a value should be popped off the stack.
|
||||
Corresponding to the `top` component, the circuit will have a set of
|
||||
output wires: if the stack is empty, the wires will represent the value
|
||||
`Nothing`, and if the stack is non-empty and $v$ is the value at the top
|
||||
of the stack, the wires will represent `Maybe` $v$.
|
86
content/chapter4/page5.md
Normal file
86
content/chapter4/page5.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
+++
|
||||
title = "`class` declarations"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
The general concepts behind classes, instances, overloading etc. were
|
||||
introduced in section [2.1](fixme). A new class is declared using the
|
||||
following:
|
||||
|
||||
```
|
||||
topDefn ::= class [ context => ] classId {tyVarId }[ | funDep ] where {
|
||||
{varId :: ctxType ; }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
*classId* is the newly declared class. It can be polymorphic, if
|
||||
*tyVarId*'s exist; these are called the *parameters* of the type class.
|
||||
The *tyVarId*'s may themselves be constrained by *context*, in which
|
||||
case the classes named in *context* are called the "super-classes" of
|
||||
this class. The "*varId*`::`*ctxType*" list declares the class method
|
||||
names and their types.
|
||||
|
||||
Example (from the Prelude):
|
||||
|
||||
```hs
|
||||
class Literal a where
|
||||
fromInteger :: Integer -> a
|
||||
```
|
||||
|
||||
This defines the class `Literal`. It says that any type `a` in this
|
||||
class must have a method (a function) called `fromInteger` that converts
|
||||
an `Integer` value into the type `a`. In fact, this is the mechanism the
|
||||
BH uses to interpret literal constants, e.g., to resolve whether a
|
||||
literal like `6`847 is to be interpreted as a signed integer, an
|
||||
unsigned integer, a floating point number, a bit value of 10 bits, a bit
|
||||
value of 8 bits, etc. (This is described in more detail in Section
|
||||
[5.3](fixme).)
|
||||
|
||||
|
||||
Example (from the Prelude):
|
||||
|
||||
```hs
|
||||
class (Literal a) => Arith a where
|
||||
(+) :: a -> a -> a
|
||||
(-) :: a -> a -> a
|
||||
negate :: a -> a
|
||||
(*) :: a -> a -> a
|
||||
```
|
||||
|
||||
|
||||
This defines the class `Arith` with super-class `Literal`. It says that
|
||||
for any type `a` that is a member of the class `Arith`, it must also be
|
||||
a member of the class `Literal`, and it must have four methods with the
|
||||
given names and types. Said another way, an `Arith` type must have a way
|
||||
to convert integer literals into that type, and it must have addition,
|
||||
subtraction, negation and multiplication defined on it.
|
||||
|
||||
|
||||
The optional *funDep* section specifies *functional dependencies*
|
||||
between the parameters of the type class:
|
||||
|
||||
```
|
||||
funDep ::= { {tyVarId }-> {tyVarId }, }
|
||||
```
|
||||
|
||||
These declarations specify that a type parameter may be determined
|
||||
uniquely by certain other type parameters. For example:
|
||||
|
||||
```hs
|
||||
class Add x y z | x y -> z, y z -> x, z x -> y
|
||||
```
|
||||
|
||||
Here, the class declaration says that for any triple of types `x`, `y`
|
||||
and `z` that are in the class `Add`, any two of the types uniquely
|
||||
determines the remaining type, *i.e.,*
|
||||
|
||||
- x and y uniquely determine z,
|
||||
- y and z uniquely determine x, and
|
||||
- z and z uniquely determine y.
|
||||
|
||||
See section [8.1](fixme) for more detailed insights into
|
||||
the use of functional dependencies.
|
||||
|
||||
> **NOTE:**
|
||||
> Functional dependencies are not currently checked by the compiler.
|
113
content/chapter4/page6.md
Normal file
113
content/chapter4/page6.md
Normal file
|
@ -0,0 +1,113 @@
|
|||
+++
|
||||
title = "`instance` declarations"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
A type can be declared as an instance of a class in two ways. The
|
||||
general mechanism is the `instance` declaration; a convenient shortcut
|
||||
that can sometimes be used is the `deriving` mechanism.
|
||||
|
||||
The general `instance` declaration grammar is the following:
|
||||
|
||||
```
|
||||
topDefn ::= instance context => classId {type }where
|
||||
{ {localDefn ; }}
|
||||
```
|
||||
|
||||
This can be read as saying that the type *type* is an instance of class
|
||||
*classId*, provided the constraints of *context* hold, and where the
|
||||
*localDefn*'s specify the implementation of the methods of the class.
|
||||
|
||||
Sometimes, when a new type is defined using a `data` declaration, it can
|
||||
simultaneously be made a member of certain useful, predefined classes,
|
||||
allowing the compiler to choose the "obvious" implementation of the
|
||||
class methods. This is done using the `deriving` qualification to a
|
||||
`data` declaration (described in section
|
||||
[4.1](fixme)) or to a
|
||||
`struct` declaration (described in section
|
||||
[4.2](fixme)). The only classes for which `deriving` can
|
||||
be used for general types are `Bits`, `Eq` and `Bounded`. Furthermore,
|
||||
`deriving` can be used for any class if the type is a data type that is
|
||||
isomorphic to a type that has an instance for the derived class.
|
||||
|
||||
### Deriving `Bits` {#sec-deriving-Bits}
|
||||
|
||||
The instances derived for the `Bits` class can be described as follows:
|
||||
|
||||
- For a `struct` type it is simply the the concatenation of the bits for
|
||||
all the fields. The first field is in the leftmost (most significant)
|
||||
bits, and so on.
|
||||
- For a `data` type, all values of the type occupy the same number of
|
||||
bits, regardless of which disjunct (constructor) it belongs to. This
|
||||
size is determined by the largest disjunct. The leftmost (most
|
||||
significant) bits are a code (a tag) for the constructor. As few bits as
|
||||
possible are used for this. The first constructor in the definition is
|
||||
coded 0, the next constructor is coded 1, and so on. The size of the
|
||||
rest of the bits is determined by the largest numbers of bits needed to
|
||||
encode the fields for the constructors. For each constructor, the fields
|
||||
are laid out left to right, and the concatenated bits are stored right
|
||||
justified (*i.e.,* at the least significant bits). For disjuncts that
|
||||
are smaller than the largest one, the bits between the constructor code
|
||||
and the field bits, if any, are "don't care" bits.
|
||||
|
||||
Examples: The type
|
||||
|
||||
```hs
|
||||
data Bool = False | True
|
||||
```
|
||||
|
||||
uses one bit. `False` is represented by 0 and `True` by 1.
|
||||
|
||||
```hs
|
||||
struct Två = { första :: Bit 8; andra:: Bit 16 }
|
||||
```
|
||||
|
||||
uses 24 bits with `första` in the upper 8 bits and `andra`
|
||||
in the lower 16.
|
||||
|
||||
```hs
|
||||
data Maybe a = Nothing | Just
|
||||
```
|
||||
|
||||
a will use $1+n$ bits,
|
||||
where $n$ bits are needed to represent values of type `a`. The extra bit
|
||||
will be the most significant bit and it will be 0 (followed by $n$
|
||||
unspecified bits) for `Nothing` and 1 (followed by the $n$ bits for `a`)
|
||||
for `Just`.
|
||||
|
||||
|
||||
### Deriving `Eq`
|
||||
|
||||
|
||||
The instances derived for the `Eq` class is the natural equality for the
|
||||
type. For a struct all fields have to be equal, for a data type the
|
||||
constructors have to be equal and then all their parts.
|
||||
|
||||
|
||||
### Deriving `Bounded`
|
||||
|
||||
|
||||
An instance for `Bounded` can be derived for an enumeration type,
|
||||
*i.e.,* a data type where all constructors are niladic. The `minBound`
|
||||
will be the first constructor and the `maxBound` will be the last.
|
||||
|
||||
`Bounded` can also be derived for a `struct` type if all the field types
|
||||
of the struct are `Bounded`. The `minBound` will be the struct with all
|
||||
fields having their respective `minBound`, and correspondingly for
|
||||
`maxBound`.
|
||||
|
||||
### Deriving for isomorphic types
|
||||
|
||||
A data type with one constructor and one argument is isomorphic to its
|
||||
type argument. For such a type any one-parameter class can be used, in a
|
||||
`deriving`, for which there is an instance for the underlying type.
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
data Apples = Apple (UInt 32) deriving (Literal, Arith)
|
||||
five :: Apples
|
||||
five = 5
|
||||
eatApple :: Apples -\> Apples
|
||||
eatApple n = n - 1
|
||||
```
|
94
content/chapter4/page7.md
Normal file
94
content/chapter4/page7.md
Normal file
|
@ -0,0 +1,94 @@
|
|||
+++
|
||||
title = "Value definitions"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
A value definition defines the value of an identifier (which could be a
|
||||
function). Value definitions are the meat of a BH program.
|
||||
|
||||
Value definitions consist of a type signature followed immediately by
|
||||
one or more defining clauses:
|
||||
|
||||
```
|
||||
topDefn ::= valueDefn
|
||||
valueDefn ::= varId :: ctxType ;
|
||||
{clause ; }
|
||||
clause ::= varId
|
||||
{apat }[ when guard ]= exp
|
||||
```
|
||||
|
||||
The first line of a value definition is the type signature--- it simply
|
||||
specifies that the identifier *varId* has the type *ctxType*. Subsequent
|
||||
lines define the value, one clause at a time. The *varId*'s on the
|
||||
left-hand side of the type signature and on the left-hand side of each
|
||||
clause must all be the same, *i.e.,* they collectively define a single
|
||||
*varId*.
|
||||
|
||||
Each clause defines part of the value, using pattern matching and
|
||||
guards. If there are patterns (*apat*'s) present, then the *varId* being
|
||||
defined is a function, and the patterns represent arguments to the
|
||||
function. The *guard* is a list of arbitrary predicates that may use
|
||||
identifiers bound in the patterns (see Section [7](fixme)).
|
||||
|
||||
The clause should be read as follows: if the function *varId* is applied to
|
||||
arguments that match the corresponding *apat*'s (in which case,
|
||||
identifiers in the *apat*'s are bound to the corresponding components of
|
||||
the arguments), and if the predicates in the *guard* are true, then the
|
||||
function returns the value of the expression *exp*.
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
wordSize :: Integer
|
||||
wordSize = 16
|
||||
```
|
||||
|
||||
|
||||
This simply defines the identifier `wordSize` to have type `Integer` and
|
||||
value 16.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
not :: Bool -> Bool
|
||||
not True = False
|
||||
not False = True
|
||||
```
|
||||
|
||||
This defines the classical Boolean negation function. The type signature
|
||||
specifies that `not` is a function with argument type `Bool` and result
|
||||
type `Bool`. After that, the first clause specifies that if the argument
|
||||
matches the value `True` (*i.e.,* it *is* the value `True`), then it
|
||||
returns `False`. The final clause specifies that if the argument is
|
||||
`False` it returns `True`.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
f :: Maybe Int -> Int -> Int
|
||||
f (Just x) y when x > 10, Just y’ <- g y = x + y'
|
||||
f _ _ = 0
|
||||
```
|
||||
|
||||
(If necessary, please first remember the definition of the `Maybe` type,
|
||||
introduced in section [4.1](fixme)). The first line specifies that
|
||||
`f` is a function
|
||||
of two arguments, of type `Maybe Int` and `Int`, respectively, and that
|
||||
its result has type `Int`. The second line specifies that if the first
|
||||
argument has the form `Just x` (in which case let us call its component
|
||||
`x`), if the second argument is anything (let us call it `y`), if `x`'s
|
||||
value is greater than 10, if the result of applying `g` to `y` has the
|
||||
form `Just y’` (in which case let us call the component `y’`), then the
|
||||
result is the value of `x + y’`. In all other cases, the result is the
|
||||
value 0. The bare underscores in the second line are *wild-card*
|
||||
patterns that match anything (described in section
|
||||
[6.1](fixme)).
|
||||
|
||||
|
||||
Clauses are attempted in order, from top to bottom, proceeding to the
|
||||
next clause only if the pattern matching and guard evaluation fail.
|
||||
Within each clause, pattern matching and guard evaluation are attempted
|
||||
from left to right. If no clause succeeds, then the system will raise a
|
||||
"pattern matching error".
|
46
content/chapter4/page8.md
Normal file
46
content/chapter4/page8.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
+++
|
||||
title = "Calling foreign functions"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
A function can be declared to be foreign which means that its
|
||||
implementation is not in BH.
|
||||
|
||||
|
||||
```
|
||||
topDefn ::= foreign varId :: type [= string ] [ , ( {string }) ]
|
||||
```
|
||||
|
||||
The optional string gives the name of the external "function" to use. If
|
||||
no string is given the same name as the BH name is used. The optional
|
||||
strings in parentheses are the port names of the Verilog module that
|
||||
implements the function. Without port names positional arguments will be
|
||||
used.
|
||||
|
||||
Example:
|
||||
|
||||
```hs
|
||||
foreign countOnes :: Bit n -> Bit 32 = "pop_count"
|
||||
```
|
||||
|
||||
|
||||
A call to `countOnes` will instantiate the Verilog `pop`` ``count`
|
||||
module. It should have the same number of arguments (with the same type)
|
||||
as the BH function, *and* an additional trailing argument which is the
|
||||
result. If the function is (size) polymorphic the instantiated types
|
||||
will be used as Verilog parameters.
|
||||
|
||||
|
||||
Example: using the declaration above an action, with the type of `x`
|
||||
being `Bit 5`,
|
||||
|
||||
```hs
|
||||
y := countOnes x
|
||||
```
|
||||
|
||||
|
||||
will translate to something like
|
||||
|
||||
```hs
|
||||
pop_count #(5) ires1(R_x, I_y);
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue