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 pathusrguide.doc
5690 lines (4409 loc) · 231 KB
/
usrguide.doc
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
.co This is the `source form' of the user documentation for Gofer, to be
.co processed using my simple prn formatter before being printed.
.co
.co Mark P. Jones August 1991
.co-------------------------------------------------------------------|
.>ch00
.op
.ti Introduction to Gofer
__________ __________ __________ __________ ________
/ _______/ / ____ / / _______/ / _______/ / ____ \
/ / _____ / / / / / /______ / /______ / /___/ /
/ / /_ / / / / / / _______/ / _______/ / __ __/
/ /___/ / / /___/ / / / / /______ / / \ \
/_________/ /_________/ /__/ /_________/ /__/ \__\
Functional programming environment, Version 2.20
Copyright Mark P Jones 1991.
A N I N T R O D U C T I O N T O G O F E R
draft version only --- please report any errors, suggestions for
improvements, extensions (or deletions!) to jones-mark@cs.yale.edu
This version includes a number of small corrections
made since the original release.
--------------------------------------------------------------------
Permission to use, copy, modify, and distribute this software and its
documentation for any personal or educational use without fee is hereby
granted, provided that:
a) This copyright notice is retained in both source code and
supporting documentation.
b) Modified versions of this software are redistributed only if
accompanied by a complete history (date, author, description) of
modifications made; the intention here is to give appropriate
credit to those involved, whilst simultaneously ensuring that any
recipient can determine the origin of the software.
c) The same conditions are also applied to any software system
derived either in full or in part from Gofer.
The name "Gofer" is not a trademark, registered or otherwise, and
you are free to mention this name in published material, public and
private correspondence, or other documents without restriction or
obligation.
Gofer is provided "as is" without express or implied warranty.
--------------------------------------------------------------------
.pa
.po
.pn -100
T A B L E O F C O N T E N T S
.in contents
.pa
.pn 1
.co-------------------------------------------------------------------|
.>ch01
.ST 1. INTRODUCTION
Gofer is a functional programming environment (in other words, an
interpreter) that I have implemented for my own personal use as part of
my research into `qualified types'. Nevertheless, the system is
sufficiently complete for me to believe that Gofer may be of interest
and use to others interested in the field of functional programming.
These notes give a brief introduction to the Gofer system and include
some examples of Gofer programs. They are not the notes that I
originally intended to write, being somewhat longer and perhaps more
tutorial in nature. Nevertheless, you will not be able to learn
functional programming from this document alone. A number of useful
references are given in the reading list at the end of this document.
In particular, the book by Bird and Wadler [1] is particularly good as
a general introduction to the use, techniques and theory of functional
programming. Although their notation is a little different from the
language used by Gofer, it is a relatively straightforward task to
translate between the two, and some suggestions for this are given in a
appendix D. More importantly, the underlying semantics of Gofer do
correspond to those expected by the authors of [1].
Whereas the work involved in investigating and implementing the ideas
on which Gofer is based were motivated largely by my own program of
work, the writing of these notes has rather more to do with the hope
that Gofer will be useful to others. I would therefore be very
grateful for any feedback on any aspect of the these notes (or of the
Gofer system itself). Please let me know if you discover any errors,
or if you find particular sections of these notes rather hard to
follow. Suggestions for improvements or extensions are more than
welcome.
.pa
.co-------------------------------------------------------------------|
.>ch02
.ST 2. BACKGROUND AND ACKNOWLEDGEMENTS
The language supported by Gofer is both syntactically and semantically
similar to that of the functional programming language Haskell [5]. My
principal task in the implementation of Gofer has therefore been to
decide which features I should omit and then to implement what
remains. Features common to both include:
o Non-strict semantics (lazy evaluation).
o Higher-order functions.
o Extended polymorphic type system with support for user-defined
overloading.
o User-defined algebraic datatypes.
o Pattern matching.
o List comprehensions.
o Facilities for I/O, whilst retaining referential transparency
within a program.
For the benefit of readers familiar with Haskell, the following
features of Haskell are not supported in the standard version of Gofer:
o Modules.
o Arrays.
o Defaults for unresolved overloading.
o Derived instances of standard classes.
o Contexts in datatype definitions.
o Full range of numeric types and classes.
But Gofer is not just a partial implementation of Haskell; it also
includes a number of experimental features which extend the type system
in several ways:
o An alternative approach to type classes which avoids the need for
construction of dictionaries during the evaluation of an
expression.
o Type classes may take multiple parameters.
o Instances of type classes may be defined at arbitrary
non-overlapping types.
o Contexts may include arbitrary type expressions.
These extensions stem from my own research [8, 9, 10, 11, 12] and were
among the principal motivations for the development of Gofer. Full
details of the differences between Gofer and Haskell 1.1 are given in
appendix C.
Gofer would not have been implemented without my original introduction
to functional programming using Orwell [6], and I am particularly
grateful to Quentin Miller for answering so many of my questions about
functional programming and about the Orwell system in particular. I
should also like to mention the influence of the Haskell B. compiler
from Lennart Augustsson and Thomas Johnsson and based on their earlier
LML compiler [7].
Right from the beginning, I wanted to be able to use Gofer on a range
of machines - and in particular, on the humble PC that I use at home.
With this in mind, Gofer was actually developed on that same PC using
Borland's Turbo C 1.5 and a public domain version of the yacc parser
generator that I picked up some time ago. Gofer was also written with
some degree of portability in mind and has subsequently been compiled
to run on Sun workstations. I hope it will also be possible to port it
to other platforms. It is my intention that Gofer be distributed
complete with source code and I hope that this will be of interest to
some users.
Many of the ideas used in the back-end of the Gofer system (i.e. the
compiler and abstract machine) originate from the chapters of Simon
Peyton Jones textbook [2]; I very much doubt whether Gofer would have
been completed without frequent reference to that book. The
lambda-lifter used in Gofer is based on Thomas Johnsson's algorithm
described in [3].
On the theoretical side, I'm grateful to Phil Wadler for the
encouragement that he has given me with my work on qualified types.
Many of the basic ideas that I have used were inspired by his original
paper motivating the use of type classes [4].
.pa
.co-------------------------------------------------------------------|
.>ch03
.ST 3. STARTING GOFER
The Gofer interpreter is usually entered by giving the command `gofer',
after which a display something like the following will normally be
produced:
Gofer Version 2.20
Reading script file "/gofer/prelude":
Parsing........................................................
Dependency analysis............................................
Type checking..................................................
Compiling......................................................
Gofer session for:
/gofer/prelude
Type :? for help
?
The file name "/gofer/prelude" mentioned in the output above is the
name of a file of standard definitions which are loaded into Gofer each
time that the interpreter is started. By default, Gofer reads these
definitions from a file called "prelude" in the current working
directory. Alternatively you can set the environment variable GOFER to
the name of the standard prelude file, which will then be used,
whatever the current working directory might be.
Most commands in Gofer take the form of a colon followed by one or more
characters which distinguish one command from another. There are two
commands which are particularly worth remembering:
o :q exits the Gofer interpreter. On most systems, you can also
exit from Gofer by typing the end of file character (^Z on an
MS-DOS machine, usually ^D on a unix based machine).
o :? prints a list of all the commands, which can be useful if you
forget the name of the command that you want to use.
The complete range of commands supported by the Gofer interpreter is
described in appendix F.
Note that the interrupt key (^C on most systems) can be used at any
time whilst using Gofer to abandon the process of reading in a file of
function definitions or the evaluation of an expression. When the
interrupt key is detected, Gofer prints the string "{Interrupted!}" and
prints the "? " prompt so that further commands can be entered.
.pa
.co-------------------------------------------------------------------|
.>ch04
.ST 4. USING GOFER - A BASIC INTRODUCTION
Using Gofer is rather like using a high-level programmable calculator;
Once the interpreter is loaded, the system prints a prompt "?" and
waits for you to enter an expression, and then press the enter (return)
key. Once the input is complete, Gofer evaluates the expression and
prints its value on the terminal, before returning to the original
prompt and waiting for the next expression. For example:
? (2+3)*8
40
(5 reductions, 9 cells)
? sum [1..10]
55
(91 reductions, 130 cells)
?
In the first example, the user entered the expression "(2+3)*8", which
was evaluated by Gofer and the result "40" printed on the terminal. At
the end of any calculation, Gofer displays the number of reductions (a
measure of the amount of work) and cells (a measure of the amount of
memory) that were used during the calculation. These figures can be
useful for comparing the performance of different ways of carrying out
the same calculation.
In the second example, the user typed the expression "sum [1..10]".
The notation "[1..10]" represents the list of integers between 1 and 10
inclusive, and "sum" is a standard function which can be used to
determine the sum of a list of integers. Thus the result obtained by
Gofer is:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55
We could have typed this sum into Gofer directly:
? 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
55
(10 reductions, 23 cells)
?
and this calculation is certainly more efficient as it uses only 1/9th
of the number of reductions and 1/5th of the number of cells as the
original calculation. On the other hand, the original expression is
much shorter and you are much less likely to make a mistake typing in
the expression "sum [1..200]" than you would be if you tried to enter
the sum of the integers from 1 to 200 directly.
You will learn more about the kind of expressions that can be entered
into Gofer in the rest of this document.
.pa
.co-------------------------------------------------------------------|
.>ch05
.ST 5. STANDARD AND USER-DEFINED FUNCTIONS
The function "sum" used in the examples above, and indeed the addition
and multiplication functions (+) and (*), are all standard functions
which are included as part of a large collection of functions called
the `standard prelude' which are loaded into the Gofer system each time
that you start the interpreter. Quite a number of useful calculations
can be carried out using these functions alone, but for more general
use you can also define your own functions and store the definitions in
a file so that these functions can be loaded and used by by the Gofer
system. For example, suppose that you create a file "fact" containing
the following definition:
fact n = product [1..n]
The "product" function is another standard function which can be used
to calculate the product of a list of integers, and so the line above
defines a function "fact" which calculates the factorial of its
argument. In standard mathematical notation, fact n = n! which is
usually defined informally by an equation of the form:
n! = 1 * 2 * ... * (n-1) * n
Once you become familiar with the notation used by Gofer, you will see
that the Gofer definition of the factorial function is really very
similar to this informal mathematical definition.
In order to use this definition from the Gofer interpreter, we must
first load the definitions of the file into the interpreter. The
simplest way to do this uses the ":l" command:
? :l fact
Reading script file "fact":
Parsing......................................................
Dependency analysis..........................................
Type checking................................................
Compiling....................................................
Gofer session for:
/gofer/prelude
fact
?
Notice the list of filenames displayed after "Gofer session for:"; this
tells you which files of definitions are currently being used by Gofer,
the first of which is the file containing the definitions for the
standard prelude. Since the file containing the definition of the
factorial function has now been loaded, we can make use of this
function in expressions entered to the interpreter:
? fact 6
720
(57 reductions, 85 cells)
For another example, recall the standard mathematical formula which
tells us that the number of ways of choosing r objects from a
collection of n objects is given by n! / (r! * (n-r)!). In Gofer, this
function can be defined by:
comb n r = fact n /(fact r * fact (n-r))
In order to use this function, we can either edit the file "fact" which
contains the definition of the factorial function, adding the
definition of "comb" on a new line, or we can include the definition as
part of an expression entered whilst using Gofer:
? comb 5 2 where comb n r = fact n /(fact r * fact (n-r))
10
(110 reductions, 161 cells)
?
The ability to define a function as part of an expression like this is
often quite useful. However, if the function "comb" were likely to be
wanted on a number of occasions, it would be more sensible to add its
definition to the contents of the file "fact", instead of having to
repeat the definition each time it is used.
You will learn more about the functions defined in the standard prelude
and find out how to define your own functions in the following
sections.
.pa
.co-------------------------------------------------------------------|
.>ch06
.ST 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:
:: = .. @ \ | <- -> ~ =>
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
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.
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.
.pa
.co-------------------------------------------------------------------|
.>ch07
.ST 7. BUILT-IN TYPES
An important part of Gofer is the type system which is used to detect
errors in expressions and function definitions. Starting with
primitive expressions such as numeric constants, Gofer assigns a type
to each expression that describes the kind of value represented by the
expression.
In general we write object :: type to indicate that a particular
expression has the indicated type. For example:
42 :: Int indicating that 42 is an integer (Int is the
name for the type of integer values).
fact :: Int -> Int indicating that "fact" is a function which
takes an integer argument and returns an
integer value (its factorial).
The most important property of the type system is that it is possible
to determine the type of an expression without having to evaluate it.
For example, the information given above is sufficient to determine
that fact 42 :: Int without needing to calculate 42! first.
Gofer has a wide range of built-in types, described in the following
sections. In addition, Gofer also includes facilities for defining new
types as well as types acting as abbreviations for complicated type
expressions as described in section 11.
.ST 7.1 Functions
--------------
If t1 and t2 are types then t1 -> t2 is the type of a function which,
given an argument of type t1 produces a result of type t2. A function
of type t1 -> t2 is said to have argument type t1 and result type t2.
In mathematics, the result of applying a function f to an argument x is
traditionally written as f(x). In many situations, these parentheses
are unnecessary and may be omitted when using Gofer.
e.g. if f :: t1 -> t2 and x :: t1 then f x is the result of applying
f to x and has type t2.
If t1, t2, ..., tn are type expressions then:
t1 -> t2 -> ... -> tn
can be used as an abbreviation for the type:
t1 -> (t2 -> ( ... -> tn) ...)
In a similar way, an expression of the form f x1 x2 ... xn is simply an
abbreviation for the expression ( ... ((f x1) x2) ... xn).
These two conventions allow us to deal with functions taking more than
one argument rather elegantly. For example, the type of the addition
function (+) is:
Int -> Int -> Int
In other words, "(+)" is a function which takes an integer argument and
returns a value of type (Int -> Int). For example, "(+) 5" is the
function which takes an integer value n and returns the value of the
integer n plus 5. Hence "(+) 5 4", which is equivalent to "5 + 4",
evaluates to the integer 9 as expected.
.ST 7.2 Booleans
-------------
Represented by the type "Bool", there are two boolean values written as
"True" and "False". The standard prelude includes several useful
functions for manipulating boolean values:
(&&), (||) :: Bool -> Bool -> Bool
The value of the expression b && d is True if and only if both
b and d are True. If b is False then d is not evaluated.
The value of the expression b || d is True if either of b or d
is True. If b is True then d is not evaluated.
not :: Bool -> Bool
The value of the expression not b is the opposite boolean value
to that of b; not True = False, not False = True.
Gofer includes a special form of `conditional expression' which enables
an expression to select between two alternatives according to the value
of a boolean expression:
if b then t else f
is an expression which is equivalent to t if b evaluates to True, or to
f if b evaluates to False. Note that an expression of this form is
only acceptable if b is an expression of type Bool and if the types of
t and f are the same, in which case the whole expression also has that
type.
.ST 7.3 Integers
-------------
Represented by the type "Int", the integer type includes both positive
and negative integers such as -273, 0 and 383. Like many computer
systems, the range of integer values that can be used is restricted and
calculations using large positive or negative numbers may lead to
(undetected) overflow.
A wide range of operators and functions are defined in the standard
prelude for use with integers:
(+) addition.
(*) multiplication.
(-) subtraction.
(^) raise to power.
negate unary negation. An expression of the form "-x" is treated
as the expression "negate x".
(/) integer division.
div " "
rem remainder, related to integer division by the law:
(x `div` y)*y + (x `rem` y) == x
mod modulo, like remainder except that the modulo has the same
sign as the divisor.
odd returns True if argument is odd, False otherwise.
even returns True if argument is even, False otherwise.
gcd returns the greatest common divisor of its two arguments.
lcm returns the least common multiple of its two arguments.
abs returns the absolute value of its argument.
signum returns -1, 0 or 1 indicating that its argument is negative,
zero or positive respectively.
The less familiar operators are illustrated by the following
identities:
3^4 == 81, 7 `div` 3 == 2, even 23 == False
7 `rem` 3 == 1, -7 `rem` 3 == -1, 7 `rem` -3 == 1
7 `mod` 3 == 1, -7 `mod` 3 == 2, 7 `mod` -3 == -2
gcd 32 12 == 4, abs (-2) == 2, signum 12 == 1
.ST 7.4 Floating point numbers
---------------------------
Represented by the type "Float", elements of this type can be used to
represent fractional values as well as very large or very small
quantities. Such values are however usually only accurate to a fixed
number of digits and rounding errors may occur in some calculations
making significant use of floating point quantities. A numeric value
in an input expression will only be treated as a floating point number
if it either includes a decimal point such as 3.14159, or if the number
is too large to be stored as a value of type Int. Scientific notation
may also be used to enter floating point quantities; for example 1.0e3
is equivalent to 1000.0, whilst 5.0e-2 is equivalent to 0.05.
[N.B. floating point numbers are not included in all implementations of
Gofer].
.ST 7.5 Characters
---------------
Represented by the type "Char", elements of this type represent
individual characters such as those entered at a keyboard. Character
values are written as single characters enclosed by apostrophe
characters: e.g. 'a', '0', 'Z'. Some special characters must be
entered using an `escape code'; each of these begins with a backslash
character '\', followed by one or more characters to select the
required character. Some of the most useful escape codes are:
'\\' backslash
'\'' apostrophe
'\"' double quote
'\n' newline
'\b' or '\BS' backspace
'\DEL' delete
'\t' or '\HT' tab
'\a' or '\BEL' alarm (bell)
'\f' or '\FF' formfeed
Additional escape characters include:
'\^c' control character, where c is replaced by
one of the characters:
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
For example, '\^A' represents control-A
'\number' representing the character with ASCII value
specified by the given decimal 'number'.
'\onumber' representing the character with ASCII value
specified by the given octal 'number'.
'\xnumber' representing the character with ASCII value
specified by the given 'hexadecimal' number.
'\name' named ASCII control character, where
`name' is replaced by one of the standard
ascii names e.g. `\DC3`.
In contrast with some common languages (such as C, for example)
character values are quite distinct from integers; however the standard
prelude does include functions:
ord :: Char -> Int
chr :: Int -> Char
which enable you to map a character to its corresponding ASCII value,
or from an ASCII value to the corresponding character:
? ord 'a'
97
(2 reductions, 6 cells)
? chr 65
'A'
(2 reductions, 7 cells)
?
.ST 7.6 Lists
----------
If a is a type then [a] is the type whose elements are lists of values
of type a. There are several ways of writing list expressions:
o The simplest list of any type is the empty list, written [].
o Non-empty lists can be constructed either by explicitly listing
the members of the list (for example: [1,3,10]) or by adding a
single element onto the front of another list using the (:)
operator (pronounced "cons"). These notations are equivalent:
[1,3,10] = 1 : [3,10] = 1 : 3 : [10] = 1 : 3 : 10 : []
(the (:) operator groups to the right so 1 : 3 : 10 : [] is
equivalent to (1:(3:(10:[]))) -- a list whose first element is 1,
second element is 3 and last element is 10).
The standard prelude includes a wide range of functions for
calculations involving lists. For example:
o length xs returns the number of elements in the list xs.
o xs ++ ys returns the list of elements in xs followed by the
elements in ys
o concat xss returns the list of elements in each of the lists in
xss
o map f xs returns the list of values obtained by applying the
function f to each of the values in the list xs in turn.
Here are some examples using these functions:
? length [1,3,10]
3
(15 reductions, 28 cells)
? [1,3,10] ++ [2,6,5,7]
[1, 3, 10, 2, 6, 5, 7]
(19 reductions, 77 cells)
? concat [[1], [2,3], [], [4,5,6]]
[1, 2, 3, 4, 5, 6]
(29 reductions, 93 cells)
? map ord ['H', 'e', 'l', 'l', 'o']
[72, 101, 108, 108, 111]
(22 reductions, 73 cells)
?
Note that all of the elements in a list must be of the same type, so
that an expression such as ['a', 2, False] is not permitted.
[ASIDE: At this point it might be useful to mention an informal
convention that is used by a number of functional programmers when
choosing names for variables representing elements of lists, lists
themselves, lists of lists and so on. If for example, a typical
element of a list is called x, then it is often useful to use the name
xs for a list of such values, suggesting that a list contains a number
of "x"s. Similarly, a list of lists might be called xss. Once you
have understood this convention it is much easier to remember the
relationship between the variables in the expression (x:xs) than it
would be if different names had been used such as (a:b).]
.ST 7.7 Strings
------------
A string is treated as a list of characters and the type String is
simply an abbreviation for the type [Char]. Strings are written as
sequences of characters enclosed between speech marks. All of the
escape codes that can be used for characters may also be used in a
string:
? "hello, world"
hello, world
(0 reductions, 13 cells)
? "hello\nworld"
hello
world
(0 reductions, 12 cells)
?
In addition, strings may contain the escape sequence "\&" which can be
used to separate otherwise ambiguous pairs of characters within a
string:
e.g. "\123h" represents the string ['\123', 'h']
"\12\&3h" represents the string ['\12', '3', 'h']
A string expression may be spread over a number of lines using a gap --
a non-empty sequence of space, tab and new line characters enclosed by
backslash characters:
? "hell\ \o"
hello
(0 reductions, 6 cells)
?
Notice that strings are printed differently from other values, which
gives the programmer complete control over the format of the output
produced by a program. The only values that Gofer can in fact display
on the terminal are strings. If the type of an expression entered into
Gofer is equivalent to String then the expression is printed directly
by evaluating and printing each character in the list in sequence.
Otherwise, the expression to be evaluated, e, is replaced by the
expression show' e where show' is a built-in function (defined as part
of the standard prelude) which converts any value to a printable
representation. The only way of printing a string value in the same
way as any other value is by explicitly using the show' function:
? show' "hello"
"hello"
(7 reductions, 24 cells)
?
The careful reader may have been puzzled by the fact the number of
reductions used in the first three examples above was zero. This is in
fact quite correct since these expressions are constants and no further
evaluation can be carried out. For constant expressions of any other
type there will always be at least one reduction needed to print the
value since the constant must first be translated to a printable
representation using the show' function.
Because strings are represented as lists of characters, all of the
standard prelude functions for manipulating lists can also be used with
strings:
? length "Hello"
5
(22 reductions, 36 cells)
? "Hello, " ++ "world"
Hello, world
(8 reductions, 37 cells)
? concat ["super","cali","fragi","listic"]
supercalifragilistic
(29 reductions, 101 cells)
? map ord "Hello"
[72, 101, 108, 108, 111]
(22 reductions, 69 cells)
?
.ST 7.8 Tuples and the unit type
-----------------------------
If t1, t2, ..., tn are types and n>=2, then there is a type of n-tuples
written (t1, t2, ..., tn) whose elements are also written in the form
(x1, x2, ..., xn) where the expressions x1, x2, ..., xn have types t1,
t2, ..., tn respectively.
e.g. (1, [2], 3) :: (Int, [Int], Int)
('a', False) :: (Char, Bool)
((1,2),(3,4)) :: ((Int, Int), (Int, Int))
Note that, unlike lists, the elements in a tuple may have different
types, although the number of elements in the tuple is fixed.
The unit type is written () and has a single element which is also
written as (). The unit type is of particular interest in theoretical
treatments of the type system of Gofer, although you may occasionally
find a use for it in practical programs.
.pa
.co-------------------------------------------------------------------|
.>ch08
.ST 8. ERRORS
.ST 8.1 Errors detected on input
-----------------------------
After an expression has been entered, but before any attempt is made to
evaluate it, Gofer carries out a number of checks to make sure that the
expression that you typed does not contain any errors. Here are some
examples of the kind of problem that might occur:
o Syntax errors. The most common situation in which this happens is
when you make a typing mistake, either leaving out some
characters, or perhaps pressing the wrong keys instead. In the
following example, the user has missed out a `[' character:
? sum 1..100]
ERROR: Syntax error in input (unexpected `..')
?
o Undefined variables. This happens when you enter an expression
using a variable or function name that is not defined in any of
the files of definitions loaded into Gofer. This can often mean
that you have misspelt the name of a function, or that the files
defining a function have not yet been loaded. For example:
? sum [1..n]
ERROR: Undefined variable "n"
?
o Type errors. Certain expressions are sensible only when the
functions used in those expressions are applied to values of the
appropriate type. For example, whilst the factorial function can
be used to calculate the factorial of an integer, it is clearly
meaningless to try to determine the factorial of a character
value. This kind of problem can be detected using the types of
the components of an expression. In the expression "fact 'A'", we
can see that the argument 'A' has type Char which does not match
the argument type Int of the factorial function. This error will
be detected by Gofer if you try to evaluate the expression:
? fact 'A'
ERROR: Type error in application
*** expression : fact 'A'
*** term : 'A'