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 pathch09
1056 lines (716 loc) · 36 KB
/
ch09
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 9. MORE ABOUT VALUE DECLARATIONS
9. MORE ABOUT VALUE DECLARATIONS
9.1 Simple pattern matching
----------------------------
Although the Gofer standard prelude includes many useful functions, you
will usually need to define a collection of new functions for specific
problems and calculations. The declaration of a function "f" usually
takes the form of a number of equations of the form:
f <pat1> <pat2> ... <patn> = <rhs>
(or an equivalent expression, if "f" is written as by an operator
symbol). Each of the expressions <pat1>, <pat2>, ..., <patn>
represents an argument to the function "f" and is called a `pattern'.
The number of such arguments is called the arity of "f". If "f" is
defined by more than one equation then they must be entered together
and each one must give the same arity for "f".
When a function is defined by more than one equation, it will usually
be necessary to evaluate one or more of the arguments to the function
to determine which equation applies. This process is called
`pattern-matching'. In all of the previous examples we have used only
the simplest kind of pattern -- a variable. As an example, consider
the factorial function defined in section 5:
fact n = product [1..n]
If we then wish to evaluate the expression "fact 6" we first match the
expression "6" against the pattern "n" and then evaluate the expression
obtained from "product [1..n]" by replacing the variable "n" with the
expression "6". The process of matching the arguments of a function
against the patterns in its definition and obtaining another expression
to be evaluated is called a `reduction'. Using Gofer, it is easy to
verify that the evaluation of "fact 6" takes one more reduction than
that of "product [1..6]":
? fact 6
720
(57 reductions, 85 cells)
? product [1..6]
720
(56 reductions, 85 cells)
?
Many kinds of constants such as the boolean values True and False can
also be used in patterns, as in the following definition of the
function "not" taken from the standard prelude:
not True = False
not False = True
In order to determine the value of an expression of the form "not b",
we must first evaluate the expression "b". If the result is "True"
then we use the first equation and the value of "not b" will be
"False". If the value of "b" is "False", then the second equation is
used and the value of "not b" will be "True".
21
Introduction to Gofer 9.1 Simple pattern matching
Other constants, including integers, characters and strings may also be
used in patterns. For example, if we define a function "hello" by:
hello "Mark" = "Howdy"
hello name = "Hello " ++ name ++ ", nice to meet you!"
then:
? hello "Mark"
Howdy
(1 reduction, 12 cells)
? hello "Fred"
Hello Fred, nice to meet you!
(13 reductions, 66 cells)
?
Note that the order in which the equations are written is very
important because Gofer always uses the first applicable equation. If
instead we had defined the function with the equations:
hello name = "Hello " ++ name ++ ", nice to meet you!"
hello "Mark" = "Howdy"
then the results obtained using this function would have been a little
different:
? hello "Mark"
Hello Mark, nice to meet you!
(13 reductions, 66 cells)
? hello "Fred"
Hello Fred, nice to meet you!
(13 reductions, 66 cells)
?
There are a number of other useful kinds of pattern, some of which are
illustrated by the following examples:
o Wildcard: _ matches any value at all; it is like a
variable pattern, except that there is no
way of referring to the matched value.
o Tuples: (x,y) matches a pair whose first and second
elements are called x and y respectively.
o Lists: [x] matches a list with precisely one element
called x.
[_,2,_] matches a list with precisely three
elements, the second of which is the
integer 2.
[] matches the empty list.
(x:xs) matches a non-empty list with head x and
tail xs.
o As patterns: p@(x,y) matches a pair whose first and second
components are called x and y. The
complete pair can also be referred to
22
Introduction to Gofer 9.1 Simple pattern matching
directly as p.
o (n+k) patterns: (m+1) matches an integer value greater than or
equal to 1. The value referred to by the
variable m is one less than the value
matched.
A further kind of pattern (called an irrefutable pattern) is introduced
in section 9.11.
Note that no variable name can be used more than once on the left hand
side of each equation in a function definition. The following example:
areTheyTheSame x x = True
areTheyTheSame _ _ = False
will not be accepted by the Gofer system, but should instead be defined
using the notation of guards introduced in the next section:
areTheyTheSame x y
| x==y = True
| otherwise = False
9.2 Guarded equations
----------------------
Each of the equations in a function definition may contain `guards'
which require certain conditions on the values of the function's
arguments to be met. As an example, here is a function which uses the
standard prelude function even :: Int -> Bool to determine whether its
argument is an even integer or not, and returns the string "even" or
"odd" as appropriate:
oddity n | even n = "even"
| otherwise = "odd"
In general, an equation using guards takes the form:
f x1 x2 ... xn | condition1 = e1
| condition2 = e2
.
.
| conditionm = em
This equation is used by evaluating each of the conditions in turn
until one of them evaluates to "True", in which case the value of the
function is given by the corresponding expression e on the right hand
side of the `=' sign. In Gofer, the variable "otherwise" is defined to
be equal to "True", so that writing "otherwise" as the condition in a
guard means that the corresponding expression will always be used if no
previous guard has been satisfied.
[ASIDE: in the notation of [1], the above examples would be written as:
oddity n = "even", if even n
= "odd", otherwise
23
Introduction to Gofer 9.2 Guarded equations
f x1 x2 ... xn = e1, if condition1
= e2, if condition2
.
.
= em, if conditionm
Translation between the two notations is relatively straightforward.]
9.3 Local definitions
----------------------
Function definitions may include local definitions for variables which
can be used both in guards and on the right hand side of an equation.
Consider the following function which calculates the number of distinct
real roots for a quadratic equation of the form a*x*x + b*x + c = 0:
numberOfRoots a b c | discr>0 = 2
| discr==0 = 1
| discr<0 = 0
where discr = b*b - 4*a*c
[ASIDE: The operator (==) is used to test whether two values are equal
or not. You should take care not to confuse this with the single `='
sign used in function definitions].
Local definitions can also be introduced at an arbitrary point in an
expression using an expression of the form:
let <decls> in <expr>
For example:
? let x = 1 + 4 in x*x + 3*x + 1
41
(8 reductions, 15 cells)
? let p x = x*x + 3*x + 1 in p (1 + 4)
41
(7 reductions, 15 cells)
?
9.4 Recursion with integers
----------------------------
Recursion is a particularly important and powerful technique in
functional programming which is useful for defining functions involving
a wide range of datatypes. In this section, we describe one particular
application of recursion to give an alternative definition for the
factorial function from section 5.
Suppose that we wish to calculate the factorial of a given integer n.
We can split the problem up into two special cases:
o If n is zero then the value of n! is 1.
o Otherwise, n! = 1 * 2 * ... * (n-1) * n = (n-1)! * n and so we
can calculate the value of n! by calculating the value of (n-1)!
24
Introduction to Gofer 9.4 Recursion with integers
and then multiplying it by n.
This process can be expressed directly in Gofer using a conditional
expression:
fact1 n = if n==0 then 1 else n * fact1 (n-1)
This definition may seem rather circular; in order to calculate the
value of n!, we must first calculate (n-1)!, and unless n is 1, this
requires the calculation of (n-2)! etc... However, if we start with
some positive value for the variable n, then we will eventually reach
the case where the value of 0! is required -- and this does not require
any further calculation. The following diagram illustrates how 6! is
evaluated using "fact1":
fact1 6 ==> 6 * fact1 5
==> 6 * (5 * fact1 4)
==> 6 * (5 * (4 * fact1 3))
==> 6 * (5 * (4 * (3 * fact1 2)))
==> 6 * (5 * (4 * (3 * (2 * fact1 1))))
==> 6 * (5 * (4 * (3 * (2 * (1 * fact1 0)))))
==> 6 * (5 * (4 * (3 * (2 * (1 * 1)))))
==> 6 * (5 * (4 * (3 * (2 * 1))))
==> 6 * (5 * (4 * (3 * 2)))
==> 6 * (5 * (4 * 6))
==> 6 * (5 * 24)
==> 6 * 120
==> 720
Incidentally, there are several other ways of writing the recursive
definition of "fact1" above in Gofer. For example, using guards:
fact2 n
| n==0 = 1
| otherwise = n * fact2 (n-1)
or using pattern matching with an integer constant:
fact3 0 = 1
fact3 n = n * fact3 (n-1)
Which of these you use is largely a matter of personal taste.
Yet another style of definition uses the (n+k) patterns mentioned in
section 9.1:
fact4 0 = 1
fact4 (n+1) = (n+1) * fact4 n
which is equivalent to:
fact5 n | n==0 = 1
| n>=1 = n * fact5 (n-1)
[COMMENT: Although each of the above definitions gives the same result
as the original "fact" function for each non-negative integer, the
25
Introduction to Gofer 9.4 Recursion with integers
functions can still be distinguished by the values obtained when they
are applied to negative integers:
o "fact (-1)" evaluates to the integer 1.
o "fact1 (-1)" causes Gofer to enter an infinite loop, which is only
eventually terminated when Gofer runs out of `stack space'.
o "fact4 (-1)" causes an evaluation error and prints the
message {fact4 (-1)} on the screen.
To most people, this suggests that the definition of "fact4" is perhaps
preferable to that of either "fact" or "fact1" as it neither gives the
wrong answer without allowing this to be detected nor causes a
potentially non-terminating computation.]
9.5 Recursion with lists
-------------------------
The same kind of technique that can be used to define recursive
functions with integers can also be used to define recursive functions
on lists. As an example, suppose that we wish to define a function to
calculate the length of a list. As the standard prelude already
includes such a function called "length", we will call the function
developed here "len" to avoid any conflict. Now suppose that we wish
to find the length of a given list. There are two cases to consider:
o If the list is empty then it has length 0
o Otherwise, it is non-empty and can be written in the form (x:xs)
for some element x and some list xs. Thus the original list is
one element longer than xs, and so has length 1 + len xs.
Writing these two cases out leads directly to the following definition:
len [] = 0
len (x:xs) = 1 + len xs
The following diagram illustrates the way that this function can be
used to determine the length of the list [1,2,3,4] (remember that this
is just an abbreviation for 1 : 2 : 3 : 4 : []):
len [1,2,3,4] ==> 1 + len [2,3,4]
==> 1 + (1 + len [3,4])
==> 1 + (1 + (1 + len [4]))
==> 1 + (1 + (1 + (1 + len [])))
==> 1 + (1 + (1 + (1 + 0)))
==> 1 + (1 + (1 + 1))
==> 1 + (1 + 2)
==> 1 + 3
==> 4
As further examples, you might like to look at the following
definitions which use similar ideas to define the functions product and
map introduced in earlier sections:
product [] = 1
product (x:xs) = x * product xs
26
Introduction to Gofer 9.5 Recursion with lists
map f [] = []
map f (x:xs) = f x : map f xs
9.6 Lazy evaluation
--------------------
Gofer evaluates expressions using a technique sometimes described as
`lazy evaluation' which means that:
o No expression is evaluated until its value is needed.
o No shared expression is evaluated more than once; if the
expression is ever evaluated then the result is shared between all
those places in which it is used.
The first of these ideas is illustrated by the following function:
ignoreArgument x = "I didn't need to evaluate x"
Since the result of the function "ignoreArgument" doesn't depend on the
value of its argument "x", that argument will not be evaluated:
? ignoreArgument (1/0)
I didn't need to evaluate x
(1 reduction, 31 cells)
?
In some situations, it is useful to be able to force Gofer to evaluate
the argument to a function before the function is applied. This can be
achieved using the function "strict" defined in the standard prelude;
An expression of the form "strict f x" is evaluated by first evaluating
the argument "x" and then applying the function "f" to the result:
? strict ignoreArgument (1/0)
{primDivInt 1 0}
(4 reductions, 29 cells)
?
The second basic idea behind lazy evaluation is that no shared
expression should be evaluated more than once. For example, the
following two expressions can be used to calculate 3*3*3*3:
? square * square where square = 3 * 3
81
(3 reductions, 9 cells)
? (3 * 3) * (3 * 3)
81
(4 reductions, 11 cells)
?
Notice that the first expression requires one less reduction than the
second. Excluding the single reduction step needed to convert each
integer into a string, the sequences of reductions that will be used in
each case are as follows:
27
Introduction to Gofer 9.6 Lazy evaluation
square * square where square = 3 * 3
-- calculate the value of square by reducing 3 * 3 ==> 9
-- and replace each occurrence of square with this result
==> 9 * 9
==> 81
(3 * 3) * (3 * 3) -- evaluate first (3 * 3)
==> 9 * (3 * 3) -- evaluate second (3 * 3)
==> 9 * 9
==>
Lazy evaluation is a very powerful feature of programming in a language
like Gofer, and means that only the minimum amount of calculation is
used to determine the result of an expression. The following example
is often used to illustrate this point.
Consider the task of finding the smallest element of a list of
integers. The standard prelude includes a function "minimum" which can
be used for this very purpose:
? minimum [100,99..1]
1
(809 reductions, 1322 cells)
?
(The expression [100,99..1] denotes the list of integers from 1 to 100
arranged in decreasing order, as described in section 10.1).
A rather different approach involves sorting the elements of the list
into increasing order (using the function "sort" defined in the
standard prelude) and then take the element at the head of the
resulting list (using the standard function "head"). Of course,
sorting the list in its entirety is likely to require significantly
more work than the previous approach:
? sort [100,99..1]
[1, 2, 3, 4, 5, 6, 7, 8, ... etc ..., 99, 100]
(10712 reductions, 21519 cells)
?
However, thanks to lazy-evaluation, calculating just the first element
of the sorted list actually requires less work in this particular case
than the first solution using "minimum":
? head (sort [100,99..1])
1
(713 reductions, 1227 cells)
?
Incidentally, it is probably worth pointing out that this example
depends rather heavily on the particular algorithm used to "sort" a
list of elements. The results are rather different if we compare the
same two approaches used to calculate the maximum value in the list:
? maximum [100,99..1]
100
28
Introduction to Gofer 9.6 Lazy evaluation
(812 reductions, 1225 cells)
? last (sort [100,99..1])
100
(10612 reductions, 20732 cells)
?
This difference is caused by the fact that each element in the list
produced by "sort" is only known once the values of all of the
preceding elements are also known. Thus the complete list must be
sorted in order to obtain the last element.
9.7 Infinite data structures
-----------------------------
One particular benefit of lazy evaluation is that it makes it possible
for functions in Gofer to manipulate `infinite' data structures.
Obviously we cannot hope either to construct or store an infinite
object in its entirety -- the advantage of lazy evaluation is that it
allows us to construct infinite objects piece by piece as necessary
(and to reuse the storage space used by parts of the object when they
are no longer required).
As a simple example, consider the following function which can be used
to produce infinite lists of integer values:
countFrom n = n : countFrom (n+1)
If we evaluate the expression "countFrom 1", Gofer just prints the list
of integer values beginning with 1 until it is interrupted. Once each
element in the list has been printed, the storage used to hold that
element can be reused to hold later elements in the list. Evaluating
this expression is equivalent to using an `infinite' loop to print the
list of integers in an imperative programming language:
? countFrom 1
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,^C{Interrupted!}
(53 reductions, 160 cells)
?
For practical applications, we are usually only interested in using a
finite portion of an infinite data structure (just as loops in an
imperative programming language are usually terminated after finitely
many iterations). For example, using "countFrom" together with the
function "take" defined in the standard prelude, we can repeat the
calculation from section 4 to find the sum of the integers 1 to 10:
? sum (take 10 (countFrom 1))
55
(62 reductions, 119 cells)
?
[ASIDE: The expression "take n xs" evaluates to a list containing the
first n elements of the list xs (or to xs itself if the list contains
fewer than n elements). Thus "countFrom 1" generates the infinite list
of integers, "take 10" ensures that only the first ten elements are
calculated, and "sum" calculates the sum of those integers as before.]
29
Introduction to Gofer 9.7 Infinite data structures
A particular advantage of using infinite data structures is that it
enables us to describe an object without being tied to one particular
application of that object. Consider the following definition for the
infinite list of powers of two [1, 2, 4, 8, ...]:
powersOfTwo = 1 : map double powersOfTwo
where double n = 2*n
This list be used in a variety of ways; using the operator (!!) defined
in the standard prelude [xs!!n evaluates to the nth element of the list
xs], we can define a function to find the nth power of 2 for any given
integer n:
twoToThe n = powersOfTwo !! n
Alternatively, we can use the list "powersOfTwo" to define a function
mapping lists of bits (represented by integers 0 and 1) to the
corresponding decimal number: simply reverse the order of the digits,
multiply each by the corresponding power of two and calculate the sum.
Using functions from the standard prelude, this translates directly
into the definition:
binToDec ds = sum (zipWith (*) (reverse ds) powersOfTwo)
For example:
? twoToThe 12
4096
(15 reductions, 21 cells)
? binToDec [1,0,1,1,0]
22
(40 reductions, 85 cells)
?
9.8 Polymorphism
-----------------
Given the definition of "product" in section 9.5, it is easy to see
that product takes a single argument which is a list of integers and
returns a single integer value -- the product of the elements of the
list. In other words, "product" has type [Int] -> Int. On the other
hand, it is not immediately clear what the type of the function "map"
should be. Clearly the first argument of "map" must be a function and
both the second argument and the result are lists, so that the type of
"map" must be of the form:
(a -> b) -> [c] -> [d]
\______/ \___/ \___/
type of 1st type of 2nd type of result
argument "f" argument "xs" "map f xs"
But what can be said about the types a, b, c and d? One possibility
would be to choose a = b = c = d = Int which would be acceptable for
expressions such as "map fact [1,2,3,4]", but this would not be
suitable in an expression such as "map chr [65,75,32]" because the
"chr" function does not have type Int -> Int.
30
Introduction to Gofer 9.8 Polymorphism
Notice however that the argument type of "f" must be the same as the
type of elements in the second argument (i.e. a = c) since "f" is
applied to each element in that list. Similarly, the result type of
"f" must be the same as the type of elements in the result list (i.e. b
= d) since each element in this list is obtained as a result of
applying the function "f" to some value. It is therefore reasonable to
treat the "map" function as having any type of the form:
(a -> b) -> [a] -> [b]
The letters "a" and "b" used in this type expression represent
arbitrary types and are called type variables. An object whose type
includes one or more type variables can be thought of as having many
different types and is often described as having a `polymorphic type'
(literally: its type has `many shapes').
The ability to define and use polymorphic functions in Gofer turns out
to be very useful. Here are the types of some of the other polymorphic
functions which have been used in previous examples which illustrate
this point:
length :: [a] -> Int
(++) :: [a] -> [a] -> [a]
concat :: [[a]] -> [a]
Thus we can use precisely the same "length" function to determine both
the length of a list of integers as well as finding the length of a
string:
? length [1..10]
10
(98 reductions, 138 cells)
? length "Hello"
5
(22 reductions, 36 cells)
?
9.9 Higher-order functions
---------------------------
In Gofer, function values are treated in much the same way as any other
kind of value; in particular, they can be used both as arguments to,
and results of other functions.
Functions which manipulate other functions in this way are often
described as `higher-order functions'. Consider the following example,
taken from the standard prelude:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
As indicated by the type declaration, we think of the (.) operator as a
function taking two function arguments and returning another function
value as its result. If f and g are functions of the appropriate
types, then (f . g) is a function called the composition of f with g.
Applying (f . g) to a value is equivalent to applying g to that value,
31
Introduction to Gofer 9.9 Higher-order functions
and then applying f to the result [As described, far more eloquently,
by the second line of the declaration above!].
Many problems can often be described very elegantly as a composition of
other functions. Consider the problem of calculating the total number
of characters used in a list of strings. A simple recursive function
provides one solution:
countChars [] = 0
countChars (w:ws) = length w + countChars ws
? countChars ["super","cali","fragi","listic"]
20
(96 reductions, 152 cells)
?
An alternative approach is to notice that we can calculate the total
number of characters by first combining all of the words in the
argument list into a single word (using concat) and then finding the
length of that word:
? (length . concat) ["super","cali","fragi","listic"]
20
(113 reductions, 211 cells)
?
Another solution is to first find the length of each word in the list
(using the "map" function to apply "length" to each word) and then
calculate the sum of these individual lengths:
? (sum . map length) ["super","cali","fragi","listic"]
20
(105 reductions, 172 cells)
?
9.10 Variable declarations
--------------------------
A variable declaration is a special form of function definition,
almost always consisting of a single equation of the form:
var = rhs
(i.e. a function declaration of arity 0). Whereas the values defined
by function declarations of arity>0 are guaranteed to be functions, the
values defined by variable declarations may or may not be functions:
odd = not . even -- if an integer is not even then it must be odd
val = sum [1..100]
Note that variables defined like this at the top level of a file of
definitions will be evaluated using lazy evaluation. The first time we
refer to the variable "val" defined above (either directly or
indirectly), Gofer evaluates the sum of the integers from 1 to 100 and
overwrites the definition of "val" with this number. This calculation
can then be avoided for each subsequent use of "val" (unless the file
32
Introduction to Gofer 9.10 Variable declarations
containing the definition of "val" is reloaded).
? val
5050
(809 reductions, 1120 cells)
? val
5050
(1 reduction, 7 cells)
?
Because of this behaviour, we should probably try to avoid using
variable declarations where the resulting value will require a lot of
storage space. If we load a file of definitions including the line:
longList = [1..10000]
and then evaluate the expression "length longList" (eventually
obtaining the expected result of 10000), then Gofer will evaluate the
definition of "longList" and replace it with the complete list of
integers from 1 upto 10000. Unlike other memory used during a
calculation, it will not be possible to reuse this space for other
calculations without reloading the file defining "longList", or loading
other files instead.
9.11 Pattern bindings and irrefutable patterns
----------------------------------------------
Another useful way of defining variables uses `pattern bindings' which
are equations of the form:
pat = rhs
where the expression on the left hand side is a pattern as described in
section 9.1. As a simple example of pattern bindings, here is one
possible definition for the function "head" which returns the first
element in a list of values:
head xs = x where (x:ys) = xs
[The definition "head (x:_) = x" used in the standard prelude is
slightly more efficient, but otherwise equivalent.]
[ASIDE: Note that pattern bindings are treated quite differently from
function bindings (of which the variable declarations described in the
last section are a special case). There are two situations in which an
ambiguity may occur; i.e. if the left hand side of an equation is a
simple variable or an (n+k) pattern of the kind described in section
9.1. In both cases, these are treated as function bindings, the former
being a variable declaration whilst the latter will be treated as a
definition for the operator symbol (+).]
Pattern bindings are often useful for defining functions which we might
think of as `returning more than one value' -- although they are
actually packaged up in a single value such as a tuple. As an example,
33
Introduction to Gofer 9.11 Pattern bindings and irrefutable patterns
consider the function "span" defined in the standard prelude.
span :: (a -> Bool) -> [a] -> ([a],[a])
If xs is a list of values and p is a predicate, then span p xs returns
the pair of lists (ys,zs) such that ys++zs == xs, all of the elements
in ys satisfy the predicate p and the first element of zs does not
satisfy p. A suitable definition, using a pattern binding to obtain
the two lists resulting from the recursive call to "span" is as
follows:
span p [] = ([],[])
span p xs@(x:xs')
| p x = let (ys,zs) = span p xs' in (x:ys,zs)
| otherwise = ([],xs)
For consistency with the lazy evaluation strategy used in Gofer, the
right hand side of a pattern binding is not evaluated until the value
of one of the variables bound by that pattern is required. The
definition:
(0:xs) = [1,2,3]
will not cause any errors when it is loaded into Gofer, but will cause
an error if we attempt to evaluate the variable xs:
? xs
{v120 [1, 2, 3]}
(11 reductions, 46 cells)
?
The variable name "v120" appearing in this expression is the name of a
function called a `conformality check' which is defined automatically
by Gofer to ensure that the value on the right hand side of the pattern
binding conforms with the pattern on the left.
Compare this with the behaviour of pattern matching in function
definitions such as:
? example [1] where example (0:xs) = "Hello"
{v126 [1]}
(4 reductions, 22 cells)
?
where the equivalent of the conformality check is carried out
immediately even if none of the values of the variables in the pattern
are actually required. The reason for this difference is that the
arguments supplied to a function must be evaluated to determine which
equation in the definition of the function should be used. The error
produced by the example above was caused by the fact that the argument
[1] does not match the pattern used in the equation defining "example"
(represented by an internal Gofer function called "v126").
A different kind of behaviour can be obtained using a pattern of the
form ~pat, known as an irrefutable (or lazy) pattern. This pattern can
34
Introduction to Gofer 9.11 Pattern bindings and irrefutable patterns
initially be matched against any value, delaying the check that this
value does indeed match pat until the value of one of the variables
appearing in it is required. The basic idea (together with the method
used to implement irrefutable patterns in Gofer) is illustrated by the
identity:
f ~pat = rhs is equivalent to f v = rhs where pat=v
The following examples, based very closely on those given in the
Haskell report [5], illustrate the use of irrefutable patterns. The
variable "undefined" used in these examples is included in the standard
prelude and causes a run-time error each time it is evaluated
(technically speaking, it represents the bottom element of the relevant
semantic domain, and is the only value having all possible types):
(\ (x,y) -> 0) undefined = {undefined}
(\~(x,y) -> 0) undefined = 0
(\ [x] -> 0) [] = {v113 []}
(\~[x] -> 0) [] = 0
(\~[x, (a,b)] -> x) [(0,1),undefined] = {undefined}
(\~[x,~(a,b)] -> x) [(0,1),undefined] = (0,1)
(\ (x:xs) -> x:x:xs) undefined = {undefined}
(\~(x:xs) -> x:x:xs) undefined = {undefined}:{undefined}:{undefined}
Irrefutable patterns are not used very frequently, although they are
particularly convenient in some situations (see section 12 for some
examples). Be careful not to use irrefutable patterns where they are
not appropriate. An attempt to define a map function "map'" using:
map' f ~(x:xs) = f x : map' f xs
map' f [] = []
turns out to be equivalent to the definition:
map' f ys = f x : map f xs where (x:xs) = ys
and will not behave as you might have intended:
? map' ord "abc"
[97, 98, 99, {v124 []}, {v124 []}, {v^C{Interrupted!}
(35 reductions, 159 cells)
?
9.12 Type declarations
-----------------------
The type system used in Gofer is sufficiently powerful to enable Gofer
to determine the type of any function without the need to declare the
types of its arguments and the return value as in some programming
languages. Despite this, Gofer allows the use of type declarations of
the form:
var1, ..., varn :: type
35
Introduction to Gofer 9.12 Type declarations
which enable the programmer to declare the intended types of the
variables var1, ..., varn defined in either function or pattern
bindings. There are a number of benefits of including type
declarations of this kind in a program: