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 pathnotes228.doc
2757 lines (2169 loc) · 113 KB
/
notes228.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 release notes for Gofer 2.28
.co
.co Mark P Jones January 1993
.co-------------------------------------------------------------------|
.>release.228
-----------------------------------------------------------------------
__________ __________ __________ __________ ________
/ _______/ / ____ / / _______/ / _______/ / ____ \
/ / _____ / / / / / /______ / /______ / /___/ /
/ / /_ / / / / / / _______/ / _______/ / __ __/
/ /___/ / / /___/ / / / / /______ / / \ \
/_________/ /_________/ /__/ /_________/ /__/ \__\
Functional programming environment, Version 2.28
Copyright Mark P Jones 1993.
Release notes
-----------------------------------------------------------------------
This document is intended to be used as a supplement to the original
user manual ``An introduction to Gofer version 2.20'' and release
notes for Gofer 2.21 (previously supplied in a file called `update').
If you would like to be informed when bug-fixes or further versions
become available, please contact me at jones-mark@cs.yale.edu (if you
have not already done so) and I will add your name to the list.
Please contact me if you have any questions about the Gofer system, or
if you need some advice or help to complete a port of Gofer to a new
platform.
ACKNOWLEDGMENTS:
A lot of people have contributed to the development of Gofer 2.28 with
their support, encouragement, suggestions, comments and bug reports.
There are a lot of people to thank:
Ray Bellis Brent Benson
David Bolton Rodney Brown
Dave Cattrall Manuel Chakravarty
Rami El Charif Stuart Clayman
Andy Duncan Bernd Eckenfels
Stephen Eldridge Jeroen Fokker
Andy Gill Annius Groenink
Dipankar Gupta Guenter Huebel
Jon Hallett Kevin Hammond
Peter Hancock Ian Holyer
Andrew Kennedy Marnix Klooster
Tom Lane Hiroyuki Matsuda
Aiden McCaughey Tobias Nipkow
Rainer Orth Will Partain
Simon Peyton Jones Ian Poole
Mark Raemer Dave Rushall
Julian Seward Carol Tumey
Goran Uddeborg Gavin Wraith
Bryan Scattergood Matthew Smith
Bernard Sufrin Philip Wadler
This list isn't complete, and I apologize in advance if I have
inadvertently left your name out.
.pa
.ti Release Notes v2.28
.co-------------------------------------------------------------------|
.ST 1. MINOR ENHANCEMENTS AND BUGFIXES
The following sections list the minor enhancements and bugfixes that
have been made to Gofer since the release of Gofer version 2.23. More
significant changes are described in later sections.
.ST 1.1 Enhancements
-----------------
o For systems without the restrictions of older PCs, Gofer now uses
multiple hash tables to speed the lookup of globally defined
functions. Loading large programs into Gofer is now much faster
as a result. In one example, the time taken to load a 13,000 line
program spread across 40 individual script files was reduced by a
factor of five!
o For the most most part, internal errors (which shouldn't normally
appear anyway) no longer terminate the interpreter.
o Better handling for programs with objects whose type involves more
than 26 type variables (though whether anyone has real practical
applications for such beasts, I'm rather doubtful).
o The Gofer system now supports I/O requests GetProgName, GetArgs
and GetEnv. The first two requests don't have any sensible
interpretation within the interpreter, so GetProgName always
returns "", while GetArgs returns []. These I/O requests are most
useful when producing standalone applications with the Gofer
compiler where they do indeed give the name of the program and the
list of command line arguments as expected.
o Added primitives for direct comparison of characters. The
original definitions of character equality and ordering in terms
of the equality and ordering on integers was elegant, but for some
examples, a substantial number of the total reductions in a given
program was taken up with calls to ord, an unnecessary
distraction.
o Small improvements in the speed of execution of the runtime machine,
particularly when Gofer is compiled using the GNU C compiler.
o Enabled the use of GNU C specific options to store frequently used
global variables in CPU registers. This is perhaps most useful
for speeding up the performance of standalone applications
produced using the Gofer compiler.
o Changed definitions in standard preludes to provide overloaded
versions of sum, product, sums, products, abs, signum and (^).
Also added a genericLength function as in Haskell. Finally,
added Text as a superclass of Num, again for Haskell compatibility.
o Added a new primitive function: openfile :: String -> String that
can be used to read the contents of a file (named by the argument
string) as a (lazy) stream of characters. (The implementation is
in terms of a primitive which can also be used to implement the
hbc openFile function, provided that you also define the Either
datatype used there.)
o Added support for a simple selection of operators for monadic I/O,
mutable variables etc. based on Lambda var (developed at Yale) and
the Glasgow I/O system. I will provide more documentation on this
as soon as there is a better consensus on the names of the
datatypes and functions that should be included in systems like
this.
o The error function is now implemented using a primitive function.
o Added support for floating point primitives:
pi :: Float
sin, asin,
cos, acos,
tan, atan,
log, log10,
exp, sqrt :: Float -> Float
atan2 :: Float -> Float -> Float
truncate :: Float -> Int
o Added support for the use of GNU readline (or equivalent) library
to be used to enhance the user interface with command line
editing. See the source makefile for instructions on how to use
this.
o Added floating point support to PC version of Gofer (even the
version for humble 8086 PCs will now support floating point).
Thanks to Jeroen Fokker for this!
o I/O datatype definitions and otherwise symbol are now builtin to
the Gofer system.
o Other minor tweaks and improvements.
.ST 1.2 Bug fixes
--------------
Nobody really likes to dwell on bugs, especially when they have been
eliminated. But for those of you who want to know, here is a summary of
the bugs discovered and fixed in Gofer 2.28:
o End of file does not imply end of line (only significant on
certain systems ... I has made an assumption which happens to hold
under DOS and Unix, but was not true for other systems).
o Code generator produced incorrect code for some conditional
expressions involving local variables (fairly obscure).
o Some conditional expressions entered into the interpreter were
evaluated incorrectly, leading to unexpected evaluation errors.
o A small potential space leak concerned with saving the names of
files passed to the editor from within Gofer was eliminated.
o A subtle bug, which only occurred when a garbage collection
occurred in the middle of an attempt to update a cell with an
indirection has been fixed.
o Fixing the definitions of the div and quot operators to agree with
Haskell 1.2 (these had been changed in the transition from 1.1 to
1.2 without my noticing).
o Corrected bug in string matching code (part of the :names command)
which previously allowed "*e*p" to match with "negate"!
o Nested comments were not always handled correctly when they
occurred at the very end of a script file.
o Added new clauses to parser to improve and correct error messages
produced by some examples.
o Other miscellaneous tweaks and fixes.
There are no other currently known bugs in Gofer. But someone is bound
to find a new one within hours of the release of 2.28 if past
experience is anything to go by. If that someone is you, please let me
know!
.co-------------------------------------------------------------------|
.ST 2. USER INTERFACE EXTENSIONS
The user interface of the previous release has been extended a little
to support a range of new features, intended to make the Gofer
environment more convenient for program development. Further details
are given in the following sections.
.ST 2.1 Customizing the Gofer system
---------------------------------
Often there will be several people using Gofer on the same system. Not
everyone will want to be using the system in the same way. For example,
some users may wish to use their own version of the prelude or start the
interpreter with particular command line options.
It has always been possible to do this by installing Gofer in an
appropriate manner. But, having had more than a couple of enquiries
about this, I wanted to take some time to spell the process out more
clearly. The following description will be biased towards those people
using Gofer on Unix-like systems, but the same basic principles can be
applied with other operating systems too.
The Gofer interpreter and prelude files will typically be installed in
a given directory, accessible to all users on the system. For the sake
of this example, let's assume that this is /usr/local/lib/Gofer. Each
user could take a copy of the Gofer interpreter into their own file
space, but a much better option is for each user to use a short script
file stored somewhere on their path. For example, the path on my Unix
account includes a subdirectory called bin and I store the following
script file `gofer' in this directory:
#!/bin/sh
#
# A simple shell script to invoke the Gofer interpreter and set
# the path to the prelude file. Ultimately, you might want to
# copy this file into your own bin directory so that you can record
# your favourite command line settings or use a different prelude
# file ...
#
GOFER=/usr/local/lib/Gofer/standard.prelude
export GOFER
exec /usr/local/lib/Gofer/gofer $*
I happen to use the standard prelude file and the default settings for
all the command line options. If, for example, I wanted to use a
different prelude file, a smaller heap and omit the printing of
statistics about the number of reductions and cells used in an
evaluation, I can modify the script to reflect this:
#!/bin/sh
#
# A modified version of the above script
#
GOFER=/usr/local/lib/Gofer/simple.prelude
export GOFER
exec /usr/local/lib/Gofer/gofer -h20000 -s $*
Of course, it is also possible to keep both of these short scripts in
my bin directory, so that I have the choice of starting up Gofer in
several different configurations, depending on the kind of work I'm
going to be doing with it.
.ST 2.2 Command line options
--------------------------
Gofer 2.28 supports a number of options which can be set, either on the
command line when Gofer interpreter is started, or using the :set
command within in the interpreter. Using the :set command without any
arguments produces a list of all the command line options available:
? :set
TOGGLES: groups begin with +/- to turn options on/off resp.
s Print no. reductions/cells after eval
t Print type after evaluation
d Show dictionary values in output exprs
f Terminate evaluation on first error
g Print no. cells recovered after gc
c Test conformality for pattern bindings
l Literate scripts as default
e Warn about errors in literate scripts
i Apply fromInteger to integer literals
o Optimise use of (&&) and (||)
u Catch ambiguously typed top-level vars
. Print dots to show progress
w Always show which files loaded
1 Overload singleton list notation
k Show kind errors in full
OTHER OPTIONS: (leading + or - makes no difference)
hnum Set heap size (cannot be changed within Gofer)
pstr Set prompt string to str
rstr Set repeat last expression string to str
Current settings: +sfceow1 -tdgliu.k -h100000 -p? -r$$
?
Most of these are the same as in the previous release of Gofer. The
following sections outline the few changes that have been made. The
`1' and `k' toggles are for use with constructor classes and will be
described in Section 4.
.ST 2.2.1 Print dots to show progress
----------------------------------
One of the first differences that you might notice when running the
new version of Gofer is that the rows of dots printed when loading a
script file:
? :l examples
Reading script file "examples":
Parsing....................................
Dependency analysis........................
Type checking..............................
Compiling..................................
Gofer session for:
/usr/local/lib/Gofer/standard.prelude
examples
?
are no longer printed while script files are loaded. The rows of dots
are useful for showing progress on slow machines (like the PC on which
Gofer was originally developed) where it is reassuring to know that the
system has not crashed, and is simply working its way through one
particular phase of the system. However, on a faster system, the dots
are not necessary and printing them can impose a surprising overhead on
the time it takes to load files. As a default, Gofer now simply prints
the names of each phase (Parsing, Dependency Analysis, Type checking
and Compiling) and, when that phase is complete, backspaces over it to
erase it from the screen. If you are fortunate enough to be using a
fast machine, you may not always see the individual words as they flash
past. After loading a file, your screen will typically look something
like this:
? :l examples
Reading script file "examples":
Gofer session for:
/usr/local/lib/Gofer/standard.prelude
examples
?
On some systems, the use of backspace characters to erase a line may
not work properly. One particular example of this occurs if you try to
run Gofer from within emacs. In this case, you may prefer to use the
original setting, printing the lines of dots by giving the command:
:set +.
The default setting is (as illustrated above, :set -.). In practice,
you will probably want to include the appropriate setting for this
option in your startup script (see Section 2.1).
.ST 2.2.2 Always show which files loaded
-------------------------------------
Some people may feel that the list of filenames printed by Gofer after
successfully loading one or more script files is redundant. This is
particularly likely if you are using the (usually default) :set -.
option since the list of files loaded will probably still be on the
screen. The list of filenames can be suppressed using the :set -w
option as follows:
? :l examples
Reading script file "examples":
Gofer session for:
/usr/local/lib/Gofer/standard.prelude
examples
? :set -w
? :l examples
Reading script file "examples":
?
The default setting can be recovered using a :set +w command.
Note that you can also use the :info command (without any arguments) as
described in Section 2.3.2 to find out the list of files loaded into the
current Gofer session. This should be particularly useful if you choose
the :set -w option.
.ST 2.2.3 Set repeat string
------------------------
The previous expression entered into the Gofer system can be recalled
as part of the next expression using the symbol $$:
? map (1+) [1..10]
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
(101 reductions, 189 cells)
? filter even $$
[2, 4, 6, 8, 10]
(130 reductions, 215 cells)
?
This feature was provided and documented in the previous release of
Gofer. However, it is possible that you may prefer to use a different
character string. This is the purpose of the -rstr option which sets
the repeat string to str. For example, user's of SML might be more
comfortable using:
? :set -rit
? 6*7
42
(3 reductions, 7 cells)
? it + it
84
(4 reductions, 11 cells)
?
Another reason for making this change might be that you have a program
which uses the symbol $$ as an operator. Each occurrence of the $$ symbol
in a script file will be interpreted as the correct operator, whatever
the value of the repeat string. But, if the default :set -r$$ setting is
used, any occurrence of $$ in an expression entered directly to the
evaluator will be taken as a reference to the previous expression.
Note that the repeat string must be either a valid Haskell identifier or
symbol, although it will always be parsed as an identifier. If the
repeat string is set to a value which is neither an identifier or symbol
(for example, :set -r0) then the repeat last expression facility will be
disabled altogether.
.ST 2.2.4 Other changes
--------------------
Comparing the list of command line options in Section 2.2 with the list
produced by previous versions of Gofer will reveal some other small
differences not already mentioned above. The changes are as follows:
o The default setting for the d toggle (show dictionaries in output
expressions) has been changed to off (:set -d). For a lot of
people, the appearance of dictionary values was rather confusing
and of little use. If you still want to see how dictionary values
are used, you will need to do :set +d or add the +d argument to
your startup script.
o The default setting for the e toggle (warn about errors in
literate scripts) has been changed to :set +e for closer
compatibility with the literate script convention outline in the
Haskell report, version 1.2. In addition, the setting of the l
toggle is now used only as a default if no particular type of
script file is specified by the file extension of a give script.
See Section 2.4 below for further details.
o The default setting for the f toggle (terminate evaluation on
first error) has been changed to :set +f. The old setting of
:set -f is, in my opinion, better for debugging purposes, but
does not give the behaviour that those using Haskell might
expect. This has caused a certain amount of confusion and was
the motivation for this change.
o The following three command line options, provided in previous
versions of Gofer, have now been removed:
TOGGLES:
a Use any evidence, not nec. best
E Fail silently if evidence not found
OTHER OPTIONS:
xnum Set maximum depth for evidence search
These options were only ever used for my own research and were
(intentionally) undocumented, so it seemed sensible to remove them
from the distributed system. A quick patch to the source code and
a recompilation is all that is necessary to reinstate these
options; useful if somebody out there found out about these
options and actually uses them (if you do, I'd love to know
why!).
.ST 2.3 Commands
-------------
The full list of commands that can be used from within the Gofer
interpreter are summarized using the command :? as follows:
? :?
LIST OF COMMANDS: Any command may be abbreviated to :c where
c is the first character in the full name.
:load <filenames> load scripts from specified files
:load clear all files except prelude
:also <filenames> read additional script files
:reload repeat last load command
:project <filename> use project file
:edit <filename> edit file
:edit edit last file
<expr> evaluate expression
:type <expr> print type of expression
:? display this list of commands
:set <options> set command line options
:set help on command line options
:names [pat] list names currently in scope
:info <names> describe named objects
:find <name> edit file containing definition of name
:!command shell escape
:cd dir change directory
:quit exit Gofer interpreter
?
Almost all of these commands are the same as in the previous release.
The only new features are listed in the following sections.
.ST 2.3.1 Shell escapes
--------------------
The shell escape command :! is used to enable you to run other programs
from within the Gofer interpreter. For example, on a Unix system, you
can print a list of all the files in the current directory by typing:
? :!ls
<list of all files in current directory gets printed here>
?
The same thing can be achieved on a PC running DOS by typing:
? :!dir
<list of all files in current directory gets printed here>
?
This is the same as in previous releases of Gofer; the only difference
is that there is no longer any need to type a space between the :!
command and the shell command that follows it. In fact, there is no
longer any need to type the leading colon either. Thus the two commands
above could equally well have been entered as:
!ls
!dir
To start a new shell from within Gofer, you can use the command :! or the
abbreviated form ! -- in Unix and DOS you can return to the Gofer system
by entering the shell command `exit'. This is likely to be different if
you use Gofer on other systems.
.ST 2.3.2 Information about named values
-------------------------------------
The :info command is a new feature which is useful for obtaining
information about the values currently loaded into a Gofer session. It
can be used to display information about all kinds of different values
including:
o Datatypes: The name of the datatype and a list of its associated
constructor functions is printed:
? :info Request
-- type constructor
data Request
-- constructors:
ReadFile :: String -> Request
WriteFile :: String -> String -> Request
AppendFile :: String -> String -> Request
ReadChan :: String -> Request
AppendChan :: String -> String -> Request
Echo :: Bool -> Request
GetArgs :: Request
GetProgName :: Request
GetEnv :: String -> Request
?
o Type synonyms: Prints the name and expansion of the synonym:
? :info Dialogue
-- type constructor
type Dialogue = [Response] -> [Request]
?
If the type synonym is restricted (see Section 3.1) then the
expansion is not included in the output:
? :info Stack
-- type constructor
type Stack a = <restricted>
?
o Type classes: Lists the type class name, superclasses, member
functions and instances:
? :info Eq
-- type class
class Eq a where
(==) :: Eq a => a -> a -> Bool
(/=) :: Eq a => a -> a -> Bool
-- instances:
instance Eq ()
instance Eq Int
instance Eq Float
instance Eq Char
instance Eq a => Eq [a]
instance (Eq a, Eq b) => Eq (a,b)
instance Eq Bool
?
Note that the member functions listed for the class include the
class predicate as part of the type; the output is not intended
to be thought of as a syntactically valid class declaration.
Overlapping instance declarations (see Section 3.2) are listed in
increasing order of generality.
o Other values: for example, named functions and individual
constructor and member functions:
? :info map : <=
map :: (a -> b) -> [a] -> [b]
(:) :: a -> [a] -> [a] -- data constructor
(<=) :: Ord a => a -> a -> Bool -- class member
?
As the last example shows, the :info command can take several arguments
and prints out information about each in turn. A warning message is
displayed if there are no known references to an argument:
? :info (:)
Unknown reference `(:)'
?
This illustrates that the arguments are treated as textual names for
operators, not syntactic expressions (for example, identifiers). The
type of the (:) operator can be obtained by giving the command :info :
as above. There is no provision for including wildcard characters of
any form in the arguments of :info commands.
If a particular argument can be interpreted as, for example, a
constructor function, or a type constructor depending on context, both
possibilities are displayed. For example, loading a program containing
the definition:
data Set a = Set [a]
We obtain:
? :info Set
-- type constructor
data Set a
-- constructors:
Set :: [a] -> Set a
Set :: [a] -> Set a -- data constructor
?
If no arguments are supplied to :info, a list of all the script files
currently loaded into the interpreter will be displayed:
? :info
Gofer session for:
/usr/local/lib/Gofer/standard.prelude
examples
?
.ST 2.4 Literate scripts
---------------------
Support for literate scripts -- files in which program lines begin with
a `>' character and all other lines are treated as comments -- was
provided in previous versions of Gofer. The command line option
:set +l was used to force Gofer to treat each input file as a literate
script, while :set -l (the default) was used to treat each input file
as a standard script of definitions.
In practice, this turned out to be somewhat inconvenient, particularly
when loading combinations of files, some as literate scripts, some
without. For example, quite a few people kept two versions of the
prelude, one as a literate script, one not, so that they wouldn't have
to fiddle with the settings or using the :set commands to load files.
Gofer version 2.28 now uses a more sophisticated scheme to determine
how an input script file should be treated, based on the use of file
extensions. More specifically, any script file with a name ending in
one of the following suffixes:
.hs .has .gs .gof .prelude
will always be loaded as a normal (i.e. non-literate) script file,
regardless of the setting of the l command line option. In a similar
way, files with names ending in one of the following suffixes:
.lgs .lhs .verb .lit
will always be treated as literate scripts. The command line option l
is only used for files with names not ending in one of the above
suffixes.
For example, the commands:
:set -l
:load prog1.gs prog2 prog3.lgs
will load prog1.gs and prog2 as non-literate scripts, and then load
prog3.lhs as a literate script.
.ST 2.5 Prelude files
------------------
The Gofer system comes with a standard prelude, and a small number of
alternative preludes. These have always been there, but a lot of
people don't seem to have noticed these, so I thought I'd say a few
words about the different preludes included with Gofer: Remember that
you can always change the prelude you are using by setting the GOFER
environment variable or by modifying a startup script as described in
Section 2.1:
standard.prelude The standard Gofer prelude, using type classes
and providing the familiar range of operators
and functions.
nofloat.prelude A simplified version of the standard.prelude
which does not include any floating point
operators. This is likely to be of most use
for those using Gofer on PCs where memory is
at a premium; compiling a version of the
interpreter (or compiler runtime library)
without floating point support can give an
important saving.
simple.prelude A prelude file based on the standard prelude
but without type classes. Let me emphasize
that point: YOU CAN USE GOFER WITHOUT HAVING
TO LEARN ABOUT TYPE CLASSES :-) Some people
seem to take to the use of type classes right
from the beginning. For those that have
problems understanding the technical details
or even the motivation, the simple.prelude
can be used to get you familiar with the syntax
of the language and the basic principles.
Then you can move up to the standard.prelude
when you're ready. The principle differences
can be described by listing the types of
commonly used operators in the simple.prelude:
(==) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(<) :: a -> a -> Bool
(>=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(/=) :: a -> a -> Bool
show :: a -> String
(+) :: Int -> Int -> Int
(-) :: Int -> Int -> Int
(*) :: Int -> Int -> Int
(/) :: Int -> Int -> Int
The resulting language is closer to the system
in Bird and Wadler (and can be made closer
still by editing the simple.prelude to use
zipwith instead of zipWith etc...).
cc.prelude An extended version of the standard.prelude
including support for a number of useful
constructor classes. Most of the examples
and applications described in Section 4 are
based on this prelude.
min.prelude A minimal prelude file. If you really want to
build a very small prelude for a particular
application, start with this and add the extra
things that you need.
As you can see, the standard extension for prelude files is .prelude
and any file ending with this suffix will be read as a non-literate
script (as described in Section 2.4). Note that, even if you are using
a computer where the full name of a prelude file is not stored (for
example, on a DOS machine the standard.prelude file becomes
STANDARD.PRE) you should still specify the prelude file by its full
name to ensure that the Gofer system treats it correctly as a prelude
file.
You are also free to construct your own prelude files, typically by
modifying one of the supplied preludes described above. Anyone who
created prelude files for use with previous releases of Gofer will need
to edit these files to ensure that they will work correctly. Note in
particular that there is no longer any need to include definitions of
the I/O datatypes in programs. Furthermore, the error function should
now be bound to the primitive "primError" rather than using the old
definition of error s | False = error s.
.co-------------------------------------------------------------------|
.ST 3. LANGUAGE DIFFERENCES
This section outlines a number of small differences and extensions to
the language used by Gofer. These features are not included in the
definition of Haskell, so you shouldn't be thinking that programs
written using these features can ultimately be used with a full Haskell
system. The use of constructor classes -- a more substantial change is
described in Section 4.
.ST 3.1 Restricted type synonyms
-----------------------------
Gofer 2.28 supports a form of restricted type synonym that can be used
to restrict the expansion of the synonym to a particular set of
functions. Outside of the selected group of functions, the synonym
constructor behaves like a standard datatype. More precisely, a
restricted type synonym definition is a top level declaration of the
form:
type T a1 ... am = rhs in f1, ..., fn
where T is the name of the restricted type synonym constructor and rhs
is a type expression typically involving some of the (distinct) type
variables a1, ..., am. The same kind of restrictions that apply to
normal type synonym declarations are also applied here. The major
difference is that the expansion of the type synonym can only be used
within the binding group of one of the functions f1, ..., fn (all of
which must be defined by top-level definitions in the file containing
the restricted type synonym definition). In the definition of any
other function, the type constructor T is treated as if it had been
introduced by a definition of the form:
data T a1 ... am = ...
The original motivation for restricted type synonyms came from my work
with constructor classes as described in Section 4 and you will several
examples of this in the ccexamples.gs file in the demos/Ccexamples
directory of the standard distribution. For a simpler example,
consider the following definition of a datatype of stacks in terms of
the standard list type:
type Stack a = [a] in emptyStack, push, pop, top, isEmpty
The definitions for the five functions named here are as follows:
emptyStack :: Stack a
emptyStack = []
push :: a -> Stack a -> Stack a
push = (:)
pop :: Stack a -> Stack a
pop [] = error "pop: empty stack"
pop (_:xs) = xs
top :: Stack a -> a
top [] = error "top: empty stack"
top (x:_) = x
isEmpty :: Stack a -> Bool
isEmpty = null
The type signatures here are particularly important. For example,
since emptyStack is mentioned in the definition of the restricted type
synonym Stack, the definition of emptyStack is type correct. The
declared type for emptyStack is Stack a which can be expanded to [a],
agreeing with the type for the empty list []. However, in an expression
outside the binding group of these functions, the Stack a type is quite
distinct from the [a] type:
? emptyStack ++ [1]
ERROR: Type error in application
*** expression : emptyStack ++ [1]
*** term : emptyStack
*** type : Stack a
*** does not match : [Int]
?
The `binding group' of a value refers to the set of values whose
definitions are in the same mutually recursive group of bindings. In
particular, this does not extend to the type class system so we can
define instances such as:
instance Eq a => Eq (Stack a) where
s1 == s2 | isEmpty s1 = isEmpty s2
| isEmpty s2 = isEmpty s1
| otherwise = top s1 == top s2 && pop s1 == pop s2
As a convenience, Gofer allows the type signatures of functions
mentioned in the type synonym declaration to be specified within the
definition rather than in a different point in the script. Thus the
example above could equally well have been written as:
type Stack a = [a] in
emptyStack :: Stack a,
push :: a -> Stack a -> Stack a,
pop :: Stack a -> Stack a,
top :: Stack a -> a,
isEmpty :: Stack a -> Bool
emptyStack = []
push = (:)
pop [] = error "pop: empty stack"
pop (_:xs) = xs
top [] = error "top: empty stack"
top (x:_) = x
isEmpty = null
However, the first form is necessary when you want to define two or
more restricted type synonyms simultaneously. For example:
type Pointer = Int in allocate, deref, assign
type Heap a = [a] in newHeap, allocate, deref, assign
newHeap :: Heap a
allocate :: Heap a -> (Heap a, Pointer)
deref :: Heap a -> Pointer -> a
assign :: Heap a -> Pointer -> a -> Heap a
etc ...
The use of restricted type synonyms doesn't quite provide proper
abstract data types. For example, if you try:
? push 1 emptyStack
[1]
(5 reductions, 11 cells)
?
then the structure of the stack as a list of values is revealed by the
printing mechanism. This happens because Gofer uses the show' function
to print out a value (in this case of type Stack Int) which looks inside
the structure of the object to see how it is represented. This happens
to be most convenient for use in an interpreter as an aid to debugging.
For the purists (and the preservation of abstraction), Gofer could be
modified to apply the (overloaded) show function to printed values.
This would force the programmer to define the way in which stack values
are printed (distinct from lists) and preserve the abstraction. Without
having set up this machinery, we get:
? show (push 1 emptyStack)
ERROR: Cannot derive instance in expression
*** Expression : show (push 1 emptyStack)
*** Required instance : Text (Stack Int)
?
The Gofer compiler described in Section 5 does not implement show' and
hence enforces the abstraction.
.ST 3.2 Overlapping instance declarations
--------------------------------------
This section describes a somewhat technical extension, aimed at those
who work with type classes. Many readers may prefer to skip to the
next section at this point.
The definition of Haskell and previous versions of Gofer insist that no
two instance declarations for a given class may contain overlapping
predicates. Thus the declarations:
class CX a where c :: a -> Int
instance CX (a,Int) where c (x,y) = y
instance CX (Int,a) where c (x,y) = x
are not allowed because the two predicates overlap:
ERROR "misctest" (line 346): Overlapping instances for class "CX"
*** This instance : CX (Int,a)
*** Overlaps with : CX (a,Int)
*** Common instance : CX (Int,Int)
As the error message indicates, given an expression c (1,2) it is not
clear whether we should use the first or the second instance
declarations to evaluate this, with potentially different results, 2 or
1 respectively.
On the other hand, there are cases where this sort of thing might be
quite reasonable. For example, the standard function show prints lists
of characters as strings, but any other kind of list is printed using
the [ ... ] notation with the items separated by commas:
? show "Hello"
"Hello"
? show [True,False,True]
[True,False,True]
? show [1..10]
[1,2,3,4,5,6,7,8,9,10]
?
Haskell deals with this by an encoding using the showList function, but
a more obvious approach might be to define two instances:
instance Text a => Text [a] where ... print using [ ... ] notation
instance Text [Char] where ... print as string
Other examples might include providing optimized versions of primitives
for particular frequently use operators, or providing a default
behaviour as in:
class Eq a where (==) = error "no definition of equality specified"
Haskell requires the context of an overloaded function to be reduced to
a form where the only predicates that it contains are of the form C a.