summaryrefslogtreecommitdiff
path: root/miralib/manual/16
blob: 143a27db3843fe81aa9956abb54f4a59ce1bfc3c (plain)
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
_P_a_t_t_e_r_n_ _M_a_t_c_h_i_n_g

The notion of `pattern' plays an important role in Miranda.   There  are
three  contexts in which patterns can be used - in function definitions,
in  conformal  definitions,  and  on  the  left  of  the  `<-'  in  list
comprehensions.    We  first  explain  the  general  rules  for  pattern
formation, which are the same in all three contexts.

Patterns are built from variables  and  constants,  using  constructors.
Here are some simple examples.
	x
	3
	(x,y,3)
The  first pattern is just the variable x, the second is the constant 3,
the last example is built from two variables and a constant,  using  the
(,,)  constructor  for 3-tuples.  The components of a structured pattern
can themselves be arbitrary patterns, permitting  nested  structures  of
any depth.

A  pattern  can  also  contain  repeated  variables, e.g.  `(x,1,x)'.  A
pattern containing repeated variables matches  a  value  only  when  the
parts of the value corresponding to occurrences of the same variable are
equal.

The constructors which can be used in a pattern include those  of  tuple
formation  `(..,..)',  list formation `[..,..]', and the constructors of
any user defined Algebraic  Type  (see  separate  manual  section).   In
addition  there are special facilities for matching on lists and natural
numbers, as follows.

(Lists) The `:' operator can be used in patterns,  so  for  example  the
following three patterns are all equivalent (and will match any 2-list).
	a:b:[]
	a:[b]
	[a,b]
Note that `:' is right associative (see manual section on Operators).

(Natural numbers) It is permitted to write patterns of  the  form  `p+k'
where  p  is  a  pattern  and  k  is  a  literal integer constant.  This
construction will succeed in matching a value n, if and only if n is  an
integer  >=k,  and  in  this  case  p is bound to (n-k).  Example, `y+1'
matches  any   positive   integer,   and   `y'   gets   bound   to   the
integer-minus-one.

Note that the automatic coercion from integer to floating  point,  which
takes  place  in  expression  evaluation,  does  not  occur  in  pattern
matching.  An integer pattern such as `3' or `n+1' will  not  match  any
floating point number.  It is not permitted to write patterns containing
floating point constants.

_C_a_s_e_ _a_n_a_l_y_s_i_s

The main use of pattern matching in Miranda is in the left hand side  of
function  definitions.  In the simplest case a pattern is used simply to
provide the right hand side of the function definition  with  names  for
subcomponents of a data structure.  For example, functions for accessing
the elements of a 2-tuple may be defined,
	fst_of_two (a,b) = a
	snd_of_two (a,b) = b

More generally  a  function  can  be  defined  by  giving  a  series  of
equations,  in which the use of different patterns on the left expresses
case analysis on the argument(s).  Some simple examples
	factorial 0 = 1
	factorial(n+1) = (n+1)*factorial n

	reverse [] = []
	reverse (a:x) = reverse x ++ [a]

	last [a] = a
	last (a:x) = last x, if x~=[]
	last [] = error "last of empty list"

Many more examples can be  found  in  the  definition  of  the  standard
environment  (see  separate manual section).  Note that pattern matching
can be combined with  the  use  of  guards  (see  last  example  above).
Patterns  in  a  case  analysis  do  not  have  to be mutually exclusive
(although as a matter of programming style that is good practice) -  the
rule  is that cases are tried in order from top to bottom, and the first
equation which `matches' is used.

_C_o_n_f_o_r_m_a_l_ _d_e_f_i_n_i_t_i_o_n_s

Apart from the simple case where the pattern is a single  variable,  the
construction
	pattern = rhs

is called a `conformal definition'.  If the value of the right hand hand
side matches the structure of the given pattern, the  variables  on  the
left are bound to the corresponding components of the value.  Example
	[a,b,3] = [1,2,3]

defines  a  and b to have the values 1 and 2 respectively.  If the match
fails anywhere, all the  variables  on  the  left  are  _u_n_d_e_f_i_n_e_d.   For
example, within the scope of the definition
	(x,x) = (1,2)

the  value of x is neither 1 nor 2, but _u_n_d_e_f_i_n_e_d (i.e. an error message
will result if you try to access the value of x in any way).

As a constraint to prevent "nonsense" definitions, it is a rule that the
pattern  on the left hand side of a conformal definition must contain at
least one variable.  So e.g. `1  =  2'  is  not  a  syntactically  valid
definition.

_P_a_t_t_e_r_n_s_ _o_n_ _t_h_e_ _l_e_f_t_ _o_f_ _g_e_n_e_r_a_t_o_r_s

In a list comprehension (see separate manual entry) the bound entity  on
the  left  hand  side of an `<-' symbol can be any pattern.  We give two
simple examples - in both examples we assume x is a list of 2-tuples.

To  denote  a  similar  list but with the elements of each tuple swapped
over we can write
	[(b,a)|(a,b)<-x]

To extract from x all second elements of a 2-tuple whose first member is
17, we can write
	[ b |(17,b)<-x]

_I_r_r_e_f_u_t_a_b_l_e_ _p_a_t_t_e_r_n_s (*)
 (Technical note, for people interested in denotational semantics)

DEFINITION:- an algebraic type having only one constructor and for which
that  constructor is non-nullary (ie has at least one field) is called a
_p_r_o_d_u_c_t _t_y_p_e.  The constructor of a product type is  called  a  `product
constructor'.

Each type of n-tuple (n~=0) is also defined to be a  product  type.   In
fact it should be clear that any user defined product type is isomorphic
to a tuple type.  Example,  if we define
	wibney ::= WIB num bool
then the type wibney is isomorphic to the tuple type (num,bool).

A pattern composed only of  product-constructors  and  identifiers,  and
containing  no  repeated  identifiers, is said to be "irrefutable".  For
example `WIB p q', `(x,y,z)' and `(a,(b,c))' are  irrefutable  patterns.
We show what this means by an example.  Suppose we define f, by

	f :: (num,num,bool) -> [char]
	f (x,y,z) = "bingo"

As a result of the constraints of strong typing, f can only  be  applied
to objects of type (num,num,bool) and given any actual parameter of that
type, the above equation for f MUST match.

Interestingly, this works even if the actual parameter is an  expression
which does not terminate, or contains an error.  (For example try typing
	f undef
and you will get "bingo", not an error message.)

This is because of  a  decision  about  the  denotational  semantics  of
algebraic  types  in  Miranda  -  namely  that product types (as defined
above) correspond to the domain construction DIRECT PRODUCT (as  opposed
to  lifted  product).  This means that the bottom element of a type such
as (num,num,bool) behaves indistinguishably from (bottom,bottom,bottom).

Note that singleton types such as the empty tuple type `()', or say,
	it ::= IT
are not product types under the above definition, and therefore patterns
containing  sui-generis  constants such as () or IT are not irrefutable.
This corresponds to a semantic decision that we do NOT wish to  identify
objects such as () or IT with the bottom element of their type.

For a more detailed discussion of  the  semantics  of  Miranda  see  the
formal language definition (in preparation).

------------------------------------------------------------------------
(*) A useful discussion of the semantics of pattern-matching,  including
the  issue  of  irrefutable patterns, can be found in (chapter 4 of) the
following
   S.  L.  Peyton-Jones ``The Implementation of Functional Programming
   Languages'', Prentice Hall International, March 1987.
   ISBN 0-13-453333-X