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 pathch14
2112 lines (1421 loc) · 74.5 KB
/
ch14
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
Introduction to Gofer 14. OVERLOADING IN GOFER
14. OVERLOADING IN GOFER
One of the biggest differences between Gofer and most other programming
languages (with the exception of Haskell) is the approach to
overloading; enabling the definition and use of functions in which the
meaning of a function symbol may depend on the types of its arguments.
Like Haskell, overloading in Gofer is based around a system of type
classes which allow overloaded functions to be grouped together into
related groups of functions. Whilst the precise details of the
approach to type classes used by Gofer are quite different from those
of Haskell, both rely on the same basic ideas and use a similar syntax
for defining and using type classes. It would therefore seem possible
that experience gained with the overloading system in one language can
readily by applied to the other.
The differences embodied in the Gofer system of classes stem from my
own, theoretically based investigations into `qualified types' some of
which is detailed in references [8-12]. In my personal opinion, the
Gofer system has some significant advantages over the Haskell approach
(see [12] for details) and one of the principal motivations behind the
implementation to Gofer was to provide a way of testing such claims.
One fact which I believe has already been established using Gofer is
that the use and implementation of overloaded functions need not have
the significant effect on performance that was anticipated with early
implementations of Haskell.
This section outlines the system of type classes used in Gofer,
indicating briefly how they can be used and how they are implemented.
14.1 Type classes and predicates
--------------------------------
A type class can be thought of as a family of types (or more generally
as a family of tuples of types) whose elements are called instances of
the class. If C is the name of an n-parameter type class then an
expression of the form C t1 t2 ... tn where t1, t2, ..., tn are type
expressions is called a predicate and represents the assertion that the
specified tuple of types is an instance of the class C.
Given a polymorphic function (e.g. map::(a->b)->[a]->[b]), we are free
to use the function at any type which can be obtained by substituting
arbitrary types for each of the type variables in its type. In Gofer,
a type expression may be qualified by one or more predicates which
restrict the range of types at which a value can be used:
e.g. a function of type C a => a -> a -> a can be treated as a function
of type t -> t -> t for any instance t of the class C.
The predicate C a in the type expression in the previous example is
called the context of the type. Contexts may contain more than one
predicate in which case the predicates involved must be separated by
commas and the context enclosed in parentheses as in (C a, D b). The
empty context is written () and any type expression t is equivalent to
the qualified type () => t. For uniformity, a context with only one
element may also be enclosed by parentheses.
61
Introduction to Gofer 14.1 Type classes and predicates
For technical reasons, type synonyms are not currently permitted in
predicates. This is consistent with the use of predicates in Haskell,
but may be relaxed, at least in certain cases, in later versions of
Gofer.
14.2 The type class Eq
----------------------
The type class Eq is a simple and useful example, whose instances are
precisely those types whose elements can be tested for equality. The
declaration of this class given in the standard prelude is as follows:
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
There are three parts in any class declaration. For this particular
example we have:
o The first line (called the `header') of the declaration introduces
a name Eq for the class and indicates that it has a single
parameter, represented by the type variable a.
o The second line of the declaration (the `signature part')
indicates that there are functions denoted by the operator symbols
(==) and (/=) of type a -> a -> Bool for each instance a of class
Eq. Using the notation introduced in the previous section, both
of these operators have type:
Eq a => a -> a -> Bool
These functions are called the `members' (or `member functions')
of the class. [This terminology, taken from Haskell, is rather
unfortunate; thinking of a type class as a set of types, the
elements of the class are called `instances', whilst the `members'
of the class correspond more closely to the instance variables
that are used in the terminology of object-oriented programming.]
The intention is that the (==) function will be used to implement
an equality test for each instance of the class, with the (/=)
operator providing the corresponding inequality function. The
ability to include related groups of functions within a single
type class in this way is a useful tool in program design.
o The third line of the class declaration (the `default
definitions') provides a default definition of the (/=) operator
in terms of the (==) operator. Thus it is only necessary to give
a definition for the (==) operator in order to define all of the
member functions for the class Eq. It is possible to override
default member definitions by giving an alternative definition as
appropriate for specific instances of the class.
62
Introduction to Gofer 14.2.1 Implicit overloading
14.2.1 Implicit overloading
---------------------------
Member functions are clearly marked as overloaded functions by their
definition as part of a class declaration, but this is not the only way
in which overloaded functions occur in Gofer; the restriction to
particular instances of a type class is also carried over into the type
of any function defined either directly or indirectly in terms of the
member functions of that class. For example, the types inferred for
the following two functions:
x `elem` xs = any (x==) xs
xs `subset` ys = all (`elem` ys) xs
are:
elem :: Eq a => a -> [a] -> Bool
subset :: Eq a => [a] -> [a] -> Bool
[ASIDE: On the other hand, if none of the functions used in a
particular expression or definition are overloaded then there will not
be any overloading in the corresponding value. Gofer does not support
the concept of implicit overloading used in some languages where a
value of a particular type might automatically be coerced to a value of
some supertype. An example of this would be the automatic translation
of a badly typed expression "1.0 == 1" to a well-typed expression of
the form "1.0 == float 1" for some (potentially overloaded) coercion
function "float" mapping numeric values to elements of type Float.]
Note also that the types appearing in the context of a qualified type
reflect the types at which overloaded functions are used. Thus:
f x ys = [x] == ys
has type Eq [a] => a -> [a] -> Bool, and not Eq a => a -> [a] -> Bool,
which is the type that would be assigned to "f" in a Haskell system.
14.2.2 Instances of class Eq
----------------------------
Instances of a type class are defined using declarations similar to
those used to define the corresponding type class. The following
examples, taken from the standard prelude, give the definitions for a
number of simple instances of the class Eq:
instance Eq Int where (==) = primEqInt
instance Eq Bool where
True == True = True
False == False = True
_ == _ = False
instance Eq Char where c == d = ord c == ord d
instance (Eq a, Eq b) => Eq (a,b) where
(x,y) == (u,v) = x==u && y==v
63
Introduction to Gofer 14.2.2 Instances of class Eq
instance Eq a => Eq [a] where
[] == [] = True
[] == (y:ys) = False
(x:xs) == [] = False
(x:xs) == (y:ys) = x==y && xs==ys
The interpretation of these declarations is as follows:
o The first declaration makes Int an instance of class Eq. The
function "primEqInt" is a primitive Gofer function which tests the
equality of two integer values and has type Int -> Int -> Bool.
o The second declaration makes Bool an instance of class Eq with a
simple definition involving pattern matching.
o The third declaration makes Char an instance of class Eq. This
definition indicates that a pair of characters are equal if they
have the same ASCII value, which is obtained using the "ord"
function. Note that the two occurrences of the symbol (==) in the
equation:
c == d = ord c == ord d
have different meanings; the first denotes equality between
characters (elements of type Char), whilst the second denotes
equality between integers (elements of type Int).
o The fourth declaration provides an equality operation on pairs.
Given two elements (x,y) and (u,v) of type (a,b) for some a, b, it
must be possible to check that both x==u and y==v before we can be
sure that the two pairs are indeed equal. In other words, both a
and b must also be instances of Eq in order to make (a,b) an
instance of Eq. This requirement is described by the first line
in the instance declaration using the expression:
(Eq a, Eq b) => Eq (a,b)
o The fifth declaration makes [a] an instance of Eq, whenever a is
itself an instance of Eq in a similar way to the previous
example. The context Eq a is used in the last equation in the
declaration:
(x:xs) == (y:ys) = x==y && xs==ys
which contains three occurrences of the (==) operator; the first
and third are used to compare lists of type [a], whilst the second
is used to compare elements of type a, using the instance Eq a.
Combining these five declarations, we obtain definitions for (==) on an
infinite family of types including Int, Char, Bool, (Int,Bool),
(Char,Int), [Char], (Bool,[Int]), [(Bool,Int)], etc...:
? 2 == 3 -- using Eq Int
False
(2 reductions, 10 cells)
? (["Hello"],3) == (["Hello"],3) -- using Eq ([[Char]],Int)
64
Introduction to Gofer 14.2.2 Instances of class Eq
True
(31 reductions, 65 cells)
?
On the other hand, any attempt to use (==) to compare elements of some
type not covered by a suitable instance declaration will result in an
error. For example, the standard prelude does not define the equality
operation on triples of values:
? (1,2,3) == (1,2,3)
ERROR: Cannot derive instance in expression
*** Expression : (==) d125 (1,2,3) (1,2,3)
*** Required instance : Eq (Int,Int,Int)
?
This can be solved by including an instance declaration of the
following form into a file of definitions loaded into Gofer:
instance (Eq a, Eq b, Eq c) => Eq (a,b,c) where
(x,y,z) == (u,v,w) = x==u && y==v && z==w
Giving:
? (1,2,3) == (1,2,3)
True
(6 reductions, 20 cells)
?
In general, an instance declaration has the form:
instance context => predicate where
definitions of member functions
The context part of the declaration gives a list of predicates which
must be satisfied for the predicate on the right hand side of the `=>'
sign to be valid. Constant predicates (i.e. predicates not involving
any type variables) required by an instance declaration (such as the
predicate Eq Int required by the third declaration) need not be
included in the context. If the resulting context is empty (as in the
first three declarations above) then it may be omitted, together with
the corresponding `=>' symbol.
14.2.3 Testing equality of represented values
---------------------------------------------
Instances of Eq can also be defined for other types, including
user-defined datatypes, and unlike the instances described above, the
definition of (==) need not be used to determine whether the values
being compared have the same structure; it is often more useful to
check that they represent the same value. As an example, suppose that
we introduce a type constructor Set for representing sets of values,
using a list to store the values held in the set:
data Set a = Set [a]
As usual, we say that two sets are equal if they have the same members,
65
Introduction to Gofer 14.2.3 Testing equality of represented values
ignoring any repetitions or differences in the ordering of the elements
in the lists representing the sets. This is achieved using the
following instance declaration:
instance Eq a => Eq (Set a) where
Set xs == Set ys = xs `subset` ys && ys `subset` xs
where xs `subset` ys = all (`elem` ys) xs
A couple of examples illustrate the use of this definition:
? Set [1,2,3] == Set [3,4,1]
False
(49 reductions, 89 cells)
? Set [1,2,3] == Set [1,2,2,2,1,3]
True
(157 reductions, 240 cells)
?
14.2.4 Instance declarations without members
--------------------------------------------
It is possible to give an instance declaration without specifying any
definitions for the member functions of the class. For example:
instance Eq ()
In this case, the definition of (==) for the instance Eq () is left
completely undefined, and hence so is the definition of (/=), which is
defined in terms of (==):
? () == ()
{undefined_member (==)}
(3 reductions, 34 cells)
? () /= ()
{undefined_member (==)}
(4 reductions, 36 cells)
?
14.2.5 Equality on function types
---------------------------------
If an expression requires an instance of a class which cannot be
obtained using the rules in the given instance declarations, then an
error message will be produced when the expression is type-checked.
For example, in general there is no sensible way to determine when a
pair of functions are equal, and the standard prelude does not include
a definition for an instance of the form Eq (a -> b) for any types a
and b:
? (1==) == (\x->1==x)
ERROR: Cannot derive instance in expression
*** Expression : (==) d148 ((==) {dict} 1) (\x->(==) {dict} 1 x)
*** Required instance : Eq (Int -> Bool)
?
66
Introduction to Gofer 14.2.5 Equality on function types
If for some reason, you would prefer this kind of error to produce an
error message when an expression is evaluated, rather than when it is
type-checked, you can use an instance declaration to specify the
required behaviour. For example:
instance Eq (a -> b) where
(==) = error "Equality not defined between functions"
Evaluating the previous expression once this instance declaration has
been included now produces the following result:
? (1==) == (\x->1==x)
{error "Equality not defined between functions"}
(42 reductions, 173 cells)
?
A limited form of equality can be defined for functions of type (a->b)
if a has only finitely many elements, such as the boolean type Bool:
instance Eq a => Eq (Bool -> a) where
f == g = f False == g False && f True == g True
[ASIDE: This instance declaration would not be accepted in a Haskell
program which insists that the predicate on the right of the `=>'
symbol contains precisely one type constructor symbol.]
Using this instance declaration once for each argument, we can now test
two functions taking boolean arguments for equality (assuming of course
that their result type is also an instance of Eq).
? (&&) == (||)
False
(9 reductions, 21 cells)
? not == (\x -> if x then False else True)
True
(8 reductions, 16 cells)
? (&&) == (\x y-> if x then y else False)
True
(16 reductions, 30 cells)
?
14.2.6 Non-overlapping instances
--------------------------------
Other instance declarations for types of the form a -> b can be used at
the same time, so long as no pair of declarations overlap. For
example, adding the following instance declaration
instance Eq a => Eq (() -> a) where f == g = f () == g ()
enables us to evaluate expressions such as:
? (\()->"Hello") == const "Hello"
True
(30 reductions, 55 cells)
?
67
Introduction to Gofer 14.2.6 Non-overlapping instances
If however, we try to use instance declarations for types of the form
(a -> b) and (Bool -> a) at the same time, then Gofer produces an error
message similar to the following:
ERROR "file" (line 37): Overlapping instances for class "Eq"
*** This instance : Eq (a -> b)
*** Overlaps with : Eq (Bool -> a)
*** Common instance : Eq (Bool -> a)
?
indicating that, given the task of testing two values of type (Bool->a)
for equality, there are (at least) two definitions of (==) that could
be used, with potentially different results being obtained in each
case.
Here is a further example of the use of non-overlapping instances of a
class to define a function "cat" (inspired by the unix (tm) command of
the same name) which uses the I/O facilities of Gofer to print the
contents of one or more files on the terminal:
class Cat a where cat :: a -> Dialogue
instance Cat [Char] where cat n = showFile n done
instance Cat [[Char]] where cat = foldr showFile done
showFile name cont = readFile name abort
(\s->appendChan stdout s abort cont)
Given these declarations, an expression of the form:
cat "file"
can be used to display the contents of the named file, whilst a list of
files can be printed one after the other using an expression of the
form:
cat ["file1", "file2", ..., "filen"].
14.3 Dictionaries
-----------------
In order to understand some of the messages produced by Gofer, as well
as some of the more subtle problems associated with overloaded
functions, it is useful to have a rough idea of the way in which
overloaded functions are implemented.
The basic idea is that a function with a qualified type context => type
where context is a non-empty list of predicates is implemented by a
function which takes an extra argument for each predicate in the
context. When the function is used, each of these parameters is filled
by a `dictionary' which gives the values of each of the member
functions in the appropriate class. None of these extra parameters is
entered by the programmer. Instead, they are inserted automatically
during type-checking.
For the class Eq, each dictionary has at least two elements containing
68
Introduction to Gofer 14.3 Dictionaries
definitions for each of the functions (==) and (/=). A dictionary for
an instance of Eq can be depicted by a diagram of the form:
+--------+--------+---------
| | |
| (==) | (/=) | .....
| | |
+--------+--------+---------
In order to produce useful error messages and indicate the way in which
dictionary expressions are being used, Gofer uses a number of special
notations for printing expressions involving dictionaries:
(#1 d) selects the first element of the dictionary d
(#2 d) selects the second element of the dictionary d
(#n d) selects the nth element of the dictionary d
(note that (#0 d) is equivalent to the dictionary d).
{dict} denotes a specific dictionary (the contents are not
displayed).
dnnn a dictionary variable representing an unknown dictionary is
printed as a lower case letter `d' followed by an integer;
e.g. d231.
Note that, whilst these notations are used in output produced by Gofer
and in the following explanations, they cannot be entered directly into
Gofer expressions or programs -- even if you use a variable such as
"d1" in an expression, Gofer will not confuse this with a dictionary
variable with the same name (although Gofer might confuse you by using
the same name in two different contexts!).
Using these notations, the member functions (==) and (/=) of the class
Eq behave as if they were defined by the expressions:
(==) d1 = (#1 d1)
(/=) d1 = (#2 d1)
To understand how these definitions work, we need to take a look at a
specific dictionary. Following the original instance declaration used
for Eq Int, the corresponding dictionary is:
d :: Eq Int
+------------+------------+
| | |
| primEqInt | defNeq d |
| | |
+------------+------------+
Note that the dictionary variable d is used as a name for the
dictionary in this diagram, indicating how values within a dictionary
can include references to the same dictionary.
[ASIDE: It turns out that predicates play a very similar role for
69
Introduction to Gofer 14.3 Dictionaries
dictionaries as types play for normal values. This motivates our use
of the notation d :: Eq Int to indicate that d is a dictionary for the
instance Eq Int. One difference between these, particularly important
for theoretical work, is that dictionary values are uniquely determined
by predicates; if d1::p and d2::p for some predicate p, then d1 = d2.]
The value held in the first element of the dictionary is the primitive
equality function on integers, "primEqInt". The following diagram
shows how the dictionary is used to evaluate the expression "2 == 3".
Note that this expression will first be translated to "(==) d 2 3" by
the type checker. The evaluation then proceeds as follows:
(==) d 2 3 ==> (#1 d) 2 3
==> primEqInt 2 3
==> False
The second element of the dictionary is a little more interesting
because it uses the default definition for (/=) given in the original
class definition which, after translation, is represented by the
function "defNeq" defined by:
defNeq d1 x y = not ((==) d1 x y)
Notice the way in which the extra dictionary parameter is used to
obtain the appropriate overloading. For example, evaluation of the
expression "2 /= 3", which becomes "(/=) d 2 3" after translation,
proceeds as follows:
(/=) d 2 3 ==> (#2 d) 2 3
==> defNeq d 2 3
==> not ((==) d 2 3)
==> not ((#1 d) 2 3)
==> not (primEqInt 2 3)
==> not False
==> True
[Clearly there is some scope for optimisation here; whilst the actual
reduction sequences used by Gofer are equivalent to those illustrated
above, the precise details are a little different.]
If an instance is obtained from an instance declaration with a
non-empty context, then the basic two element dictionary used in the
examples above is extended with an extra dictionary value for each
predicate in the context. As an example, the diagram below shows the
dictionaries that will be created from the instance definitions in
section 14.2.2 for the instance Eq (Int, [Int]). The functions
"eqPair" and "eqList" which are used in these dictionaries are obtained
from the definitions of (==) given in the instance declarations for Eq
(a,b) and Eq [a] respectively:
eqPair d (x,y) (u,v) = (==) (#3 d) x u && (==) (#4 d) y v
eqList d [] [] = True
eqList d [] (y:ys) = False
eqList d (x:xs) [] = False
eqList d (x:xs) (y:ys) = (==) (#3 d) x y && (==) d xs ys
70
Introduction to Gofer 14.3 Dictionaries
The dictionary structure for Eq (Int, [Int]) is as follows. Note that
the Gofer system ensures that there is at most one dictionary for a
particular instance of a class, and that the dictionary d1 :: Eq Int in
this system is automatically shared between d2 and d3:
d3 :: Eq (Int, [Int])
+------------+------------+------------+------------+
| | | | |
| eqPair d3 | defNeq d3 | d1::Eq Int |d2::Eq [Int]|
| | | | |
+------------+------------+-----+------+-----+------+
| |
+--------------+ |
| |
| d2 :: Eq [Int] V
| +------------+------------+------------+
| | | | |
| | eqList d2 | defNeq d2 | d1::Eq Int |
| | | | |
| +------------+------------+-----+------+
| |
d1 :: Eq Int V |
+------------+------------+ |
| | | |
| primEqInt | defNeq d1 |<--------------------------+
| | |
+------------+------------+
Once again, it may be useful to see how these definitions are used to
evaluate the expression "(2,[1]) == (2,[1,3])" which, after
translation, becomes "(==) d3 (2,[1]) (2,[1,3])":
(==) d3 (2,[1]) (2,[1,3])
==> (#1 d3) (2,[1]) (2,[1,3])
==> eqPair d3 (2,[1]) (2,[1,3])
==> (==) (#3 d3) 2 2 && (==) (#4 d3) [1] [1,3]
==> (==) d1 2 2 && (==) (#4 d3) [1] [1,3]
==> (#1 d1) 2 2 && (==) (#4 d3) [1] [1,3]
==> primEqInt 2 2 && (==) (#4 d3) [1] [1,3]
==> True && (==) (#4 d3) [1] [1,3]
==> (==) (#4 d3) [1] [1,3]
==> (==) d2 [1] [1,3]
==> (#1 d2) [1] [1,3]
==> eqList d2 [1] [1,3]
==> (==) (#3 d2) 1 1 && (==) d2 [] [3]
==> (==) d1 1 1 && (==) d2 [] [3]
==> (#1 d1) 1 1 && (==) d2 [] [3]
==> primEqInt 1 1 && (==) d2 [] [3]
==> True && (==) d2 [] [3]
==> (==) d2 [] [3]
==> False
71
Introduction to Gofer 14.3.1 Superclasses
14.3.1 Superclasses
-------------------
In general, a type class declaration has the form:
class context => Class a1 ... an where
type declarations for member functions
default definitions of member functions
where Class is the name of the new type class which takes n arguments,
represented by distinct type variables a1, ..., an. As in the case of
instance declarations, the context that appears on the left hand side
of the `=>' symbol specifies a list of predicates that must be
satisfied in order to construct any instance of "Class".
The predicates in the context part of a class declaration are called
the superclasses of Class. This terminology is taken from Haskell
where all classes have a single parameter and each of the predicates in
the context part of a class declaration has the form C a1; in this
situation, any instance of Class must also be an instance of each class
C named in the context. In other words, each such C contains a
superset of the types in Class.
As an example of a class declaration with a non-empty context, consider
the following declaration from the standard prelude which introduces a
class Ord whose instances are types with both strict (<), (>) and
non-strict (<=), (>=) versions of an ordering defined on their
elements:
class Eq a => Ord a where
(<), (<=), (>), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
x < y = x <= y && x /= y
x >= y = y <= x
x > y = y < x
max x y | x >= y = x
| y >= x = y
min x y | x <= y = x
| y <= x = y
Notice that this definition provides default definitions for all of the
member functions except (<=), so that in general only this single
function needs to be defined to construct an instance of class Ord.
There are two reasons for defining Eq as a superclass of Ord:
o The default definition for (<) relies on the use of (/=) taken
from class Eq. In order to guarantee that this is always valid we
must ensure that every instance of Ord must also be an instance of
Eq.
o Given the definition of a non-strict ordering (<=) on the elements
of a type, it is always possible to construct a definition for the
(==) operator (and hence for (/=)) using the equation:
72
Introduction to Gofer 14.3.1 Superclasses
x==y = x<=y && y<=x
There will therefore be no loss in generality by requiring Eq to
be a superclass of Ord, and conversely, no difficulty in defining
an instance of Eq to accompany any instance of Ord for which an
instance of Eq has not already be provided.
As an example, the following definitions provide an alternative
way to implement the equality operation on elements of the Set
datatype described in section 14.2.3, in terms of the subset
ordering defined in class Ord:
instance Ord (Set a) => Eq (Set a) where
x == y = x <= y && y <= x
instance Eq a => Ord (Set a) where
Set xs <= Set ys = all (`elem` ys) xs
This definition is in fact no less efficient or effective than the
original version.
Dictionaries for superclasses are dealt with in much the same way as
the instance specific dictionaries described above. For example, the
general layout of a dictionary for an instance of Ord is illustrated in
the following diagram:
+--------+--------+--------+--------+--------+--------+--------+-----
| | | | | | | |
| (<) | (<=) | (>) | (>=) | max | min | Eq a | .....
| | | | | | | |
+--------+--------+--------+--------+--------+--------+--------+-----
Note the use of the seventh element of this dictionary which points to
the dictionary for the appropriate instance of Eq. This is used in the
translation of the default definition for (<) which is equivalent to:
defLessThan d x y = (<=) d x y && (/=) (#7 d) x y
14.3.2 Combining classes
------------------------
In general, a dictionary is made up of three separate parts:
+-------------------+-------------------+-------------------+
| Implementation | Superclass | Instance specific |
| of class members | Dictionaries | Dictionaries |
| | | |
+-------------------+-------------------+-------------------+
Each of these may be empty. We have already seen examples in which
there are no superclass dictionaries (e.g. instances of Eq) and in
which there are no instance specific dictionaries (e.g. Eq Int).
Classes with no member functions (corresponding to dictionaries with no
member functions) are sometimes useful as a convenient abbreviation for
a list of predicates. For example:
73
Introduction to Gofer 14.3.2 Combining classes
class C a where cee :: a -> a
class D a where dee :: a -> a
class (C a, D a) => CandD a
makes CandD a an abbreviation for the context (C a, D a). Thinking of
single parameter type classes as sets of types, the type class CandD
corresponds to the intersection of classes C and D.
Just as the type inferred for a particular function definition or
expression does not involve type synonyms unless explicit type
signatures are used, the Gofer type system will not use a single
predicate of the form CandD a instead of the two predicates C a and D a
unless explicit signatures are used:
? :t dee . cee
\d129 d130 -> dee d130 . cee d129 :: (C a, D a) => a -> a
? :t dee . cee :: CandD a => a -> a
\d129 -> dee (#2 d129) . cee (#1 d129) :: CandD a => a -> a
?
In Haskell, all instances of a class such as CandD must have
explicit declarations, in addition to the corresponding declarations
for instances for C and D. This problem can be avoided by using the
more general form of instance declaration permitted in Gofer; a single
instance declaration:
instance CandD a
is all that is required to ensure that any instance of CandD can be
obtained, so long as corresponding instances for C and D can be found.
14.3.3 Simplified contexts
--------------------------
Consider the function defined by the following equation:
eg1 x = [x] == [x] || x == x
This definition does not restrict the type of x in any way except that,
if x :: a, then there must be instances Eq [a] and Eq a which are used
for the two occurrences of the (==) operator in the equation. We might
therefore expect the type of eg1 to be:
(Eq [a], Eq a) => a -> Bool
with translation:
eg1 d1 d2 x = (==) d1 [x] [x] || (==) d2 x x
However, as can be seen from the case where a=Int illustrated in
section 14.3, given d1::Eq [a] we can always find a dictionary for Eq a
by taking the third element of d1 i.e. (#3 d1)::Eq a. Since it is more
efficient to select an element from a dictionary than to complicate
both type and translation with extra parameters, the type assigned to
"eg1" by default is:
74
Introduction to Gofer 14.3.3 Simplified contexts
Eq [a] => a -> Bool
with translation:
eg1 d1 x = (==) d1 [x] [x] || (==) (#3 d1) x x
In general, given a set of predicates corresponding to the instances
required by an expression, Gofer will always attempt to find the
smallest possible subset of these predicates such that all of the
required dictionaries can still be obtained, whilst minimising the
number of dictionary parameters that are used.
The original type and translation for eg1 given above can be produced
by including an explicit type signature in the file containing the
definition of eg1:
eg1 :: (Eq [a], Eq a) => a -> Bool
eg1 x = [x] == [x] || x == x
But even with this definition, Gofer will still always try to minimise
the number of dictionaries used in any particular expression:
? :t eg1
\d153 -> eg1 d153 (#3 d153) :: Eq [a] => a -> Bool
?
As another example, consider the expression "(\x y-> x==x || y==y)".
The type and translation assigned to this term can be found directly
using Gofer:
? :t (\x y-> x==x || y==y)
\d121 d122 x y -> (==) d122 x x ||
(==) d121 y y
:: (Eq b, Eq a) => a -> b -> Bool
?
Note that the translation has two dictionary parameters d121 and d122
corresponding to the two predicates Eq a and Eq b respectively. Since
both of these dictionaries can be obtained from a dictionary for the
predicate Eq (a,b), we can use an explicit type signature to produce a
translation which needs only one dictionary parameter:
? :t (\x y-> x==x || y==y) :: Eq (a,b) => a -> b -> Bool
\d121 x y -> (==) (#3 d121) x x ||
(==) (#4 d121) y y
:: Eq (a,b) => a -> b -> Bool
?
75
Introduction to Gofer 14.4 Other issues
14.4 Other issues
-----------------
14.4.1 Unresolved overloading
-----------------------------