This repository was archived by the owner on Nov 6, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathch06
264 lines (167 loc) · 9.91 KB
/
ch06
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
Introduction to Gofer 6. FUNCTION NAMES - IDENTIFIERS AND OPERATORS
6. FUNCTION NAMES - IDENTIFIERS AND OPERATORS
As the examples of the previous section show, there are two kinds of
name that can be used for a function; identifiers such as "sum" and
operator symbols such as "+" and "*". Choosing the appropriate kind of
name for a particular function can often help to make expressions
involving that function easier to read. If for example the addition
function was represented by the name "plus" rather than the operator
symbol "+" then the sum of the integers from 1 to 5 would have to be
written as:
plus (plus (plus (plus 1 2) 3) 4) 5
In this particular case, another way of writing the same sum is:
plus 1 (plus 2 (plus 3 (plus 4 5)))
Not only does the use of the identifier "plus" make these expressions
larger and more difficult to read than the equivalent expressions using
"+"; it also makes it very much harder to see that these two
expressions do actually have the same value.
Gofer distinguishes between the two types of name according to the way
that they are written:
o An identifier begins with a letter of the alphabet optionally
followed by a sequence of characters, each of which is either a
letter, a digit, an apostrophe (') or an underbar (_).
Identifiers representing functions or variables must begin with a
lower case letter (identifiers beginning with an upper case letter
are used to denote a special kind of function called a
`constructor function' described in section 11.1). The following
identifiers are examples of Gofer variable and function names:
sum f f'' integerSum african_queen do'until'zero
The following identifiers are reserved words in Gofer and cannot
be used as the name of a function or variable:
case of where let in if
then else data type infix infixl
infixr primitive class instance
o An operator symbol is written using one or more of the following
symbol characters:
: ! # $ % & * + . / < = > ? @ \ ^ | -
In addition, the tilde character (~) is also permitted, although
only in the first position of an operator name. [N.B. Haskell
also makes the same restriction for the minus/dash character
(-)]. Operator names beginning with a colon are used for
constructor functions in the same way as identifiers beginning
with a capital letter as mentioned above. In addition, the
following operator symbols have special uses in Gofer:
8
Introduction to Gofer 6. FUNCTION NAMES - IDENTIFIERS AND OPERATORS
:: = .. @ \ | <- -> ~ =>
All other operator symbols can be used as variables or function
names, including each of the following examples:
+ ++ && || <= == /= // .
==> $ @@ -*- \/ /\ ... ?
[Note that each of the symbols in the first line is used in the
standard prelude. If you are interested in using Gofer to develop
programs for use with a Haskell compiler, you might also want to
avoid using the operator symbols := ! :+ and :% which are used to
support features in Haskell not currently provided by the Gofer
standard prelude.]
Gofer provides two simple mechanisms which make it possible to use an
identifier as an operator symbol, or an operator symbol as an
identifier:
o Any identifier will be treated as an operator symbol if it is
enclosed in backquotes (`) -- for example, the expressions using
the "plus" function above are a little easier to read using this
technique:
(((1 `plus` 2) `plus` 3) `plus` 4) `plus` 5
In general, an expression of the form "x `op` y" is equivalent to
the corresponding expression "op x y", whilst an expression such
as "f x y z" can also be written as "(x `f` y) z".
[NOTE: For those using Gofer on a PC, you may find that your
keyboard does not have a backquote key! In this case you should
still be able to enter a backquote by holding down the key marked
ALT, pressing the keys '9' and then '6' on the numeric keypad and
then releasing the ALT key.]
o Any operator symbol can be treated as an identifier by enclosing
it in parentheses. For example, the addition function denoted by
the operator symbol "+" is often written as "(+)". Any expression
of the form "x + y" can also be written in the form "(+) x y".
There are two more technical problems which have to be dealt with when
working with operator symbols:
o Precedence: Given operator symbols (+) and (*), should "2 * 3 + 4"
be treated as either "(2 * 3) + 4" or "2 * (3 + 4)"?
This problem is solved by assigning each operator a precedence
value (an integer in the range 0 to 9). In a situation such as
the above, we simply compare the precedence values of the
operators involved, and carry out the calculation associated
with the highest precedence operator first. The standard
precedence values for (+) and (*) are 6 and 7 respectively so that
the expression above will actually be treated as "(2 * 3) + 4".
o Grouping: The above rule is only useful when the operator symbols
9
Introduction to Gofer 6. FUNCTION NAMES - IDENTIFIERS AND OPERATORS
involved have distinct precedences. For example, should the
expression "1 - 2 - 3" be treated as either "(1 - 2) - 3" giving a
result of -4, or as "1 - (2 - 3)" giving a result of 2?
This problem is solved by giving each operator a `grouping'
(sometimes called its associativity). An operator symbol (-) is
said to:
o group to the left if "x - y - z" is treated as "(x - y) - z"
o group to the right if "x - y - z" is treated as "x - (y - z)"
A third possibility is that an expression of the form "x - y - z"
is to be treated as ambiguous and will be flagged as a syntax
error. In this case we say that the operator (-) is
non-associative.
The standard approach in Gofer is to treat (-) as grouping to the
left so that "1 - 2 - 3" will actually be treated as "(1-2)-3".
By default, every operator symbol in Gofer is treated as
non-associative with precedence 9. These values can be changed by a
declaration of one of the following forms:
infixl digit ops to declare operators which group to the left
infixr digit ops to declare operators which group to the right
infix digit ops to declare non-associative operators
In each of these declarations ops represents a list of one or more
operator symbols separated by commas and digit is an integer between 0
and 9 which gives the precedence value for each of the listed operator
symbols. The precedence digit may be omitted in which case a value of
9 is assumed. There are a number of restrictions on the use of these
declarations:
o Operator declarations can only appear in files of function
definitions which are loaded into Gofer; they cannot be entered
directly whilst using the Gofer interpreter.
o At most one operator declaration is permitted for any particular
operator symbol (even if repeated declarations all specify the
same precedence and grouping as the original declaration).
o Any file containing a declaration for an operator precedence and
grouping must also contain a (top-level) declaration for that
operator.
In theory, it is possible to use an operator declaration at any point
in a file of definitions. In practice, it is sensible to ensure that
each operator is declared before the symbol is used. One way to
guarantee this is to place all operator declarations at the beginning
of the file [this condition is enforced in Haskell]. Note that until
an operator declaration for a particular symbol is encountered, any
occurrence of that symbol will be treated as a non-associative operator
with precedence 9.
10
Introduction to Gofer 6. FUNCTION NAMES - IDENTIFIERS AND OPERATORS
The following operator declarations are taken from the standard prelude:
-- Operator precedence table
infixl 9 !!
infixr 9 .
infixr 8 ^
infixl 7 *
infix 7 /, `div`, `rem`, `mod`
infixl 6 +, -
infix 5 \\
infixr 5 ++, :
infix 4 ==, /=, <, <=, >=, >
infix 4 `elem`, `notElem`
infixr 3 &&
infixr 2 ||
and their use is illustrated by the following examples:
Expression: Equivalent to: Reasons:
----------- -------------- --------
1 + 2 - 3 (1 + 2) - 3 (+) and (-) have the same precedence
and group to the left.
x : ys ++ zs x : (ys ++ zs) (:) and (++) have the same precedence
and group to the right
x == y || z (x == y) || z (==) has higher precedence than (||).
3 * 4 + 5 (3 * 4) + 5 (*) has higher precedence than (+).
y `elem` z:zs y `elem` (z:zs) (:) has higher precedence than elem.
12 / 6 / 3 syntax error ambiguous use of (/); could mean
either (12/6)/3 or 12/(6/3).
Note that function application always binds more tightly than any infix
operator symbol. For example, the expression "f x + g y" is equivalent
to "(f x) + (g y)". Another example which often causes problems is the
expression "f x + 1", which is treated as "(f x) + 1" and not as
"f (x+1)" as is sometimes expected.
11