summaryrefslogtreecommitdiff
path: root/miralib/manual/27/4
blob: f34bc3dda72e5fb58514b0827b9ba16723ffe0cc (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
_T_h_e_ _%_f_r_e_e_ _d_i_r_e_c_t_i_v_e_ _a_n_d_ _p_a_r_a_m_e_t_r_i_s_e_d_ _s_c_r_i_p_t_s

It is permitted to construct a script containing definitions  which  are
dependent  on information which will be supplied only when the script is
made the subject of a %_i_n_c_l_u_d_e directive.  Such a script is said  to  be
_p_a_r_a_m_e_t_r_i_s_e_d.   This  is  indicated  by  the presence in the script of a
directive of the form

	%_f_r_e_e { signature }

where `signature' is a list of specifications  of  the  identifiers  for
which  bindings will be provided at %_i_n_c_l_u_d_e time.  A script may contain
at  most  one  %_f_r_e_e  directive,  which  must  therefore  give  all  the
identifiers  on  which  the script is parametrised.  The %_f_r_e_e directive
may appear anywhere in the script, but for  clarity  it  is  recommended
that you place it at or near the top.

For example a script (called "matrices"  say)  defining  the  notion  of
matrix  sum  and  matrix  product,  for  matrices  of as-yet-unspecified
element type, could be written as follows:-

	%_e_x_p_o_r_t matmult matadd

	%_f_r_e_e { elem :: _t_y_p_e
		zero :: elem
		mult, add :: elem->elem->elem
	      }
	
	matrix == [[elem]]

	matadd :: matrix->matrix->matrix
	matadd xx yy = [[add a b|(a,b)<-zip2 x y]|(x,y)<-zip2 xx yy]

	matmult :: matrix->matrix->matrix
	matmult xx yy = outerprod innerprod xx (transpose yy)
	innerprod x y = sum [mult a b|(a,b)<-zip2 x y]
			_w_h_e_r_e
			sum = foldr add zero
	outerprod f xx yy = [[f x y|y<-yy]|x<-xx]

Note that the identifiers declared under %_f_r_e_e may denote types as  well
as  values.   When we write a %_i_n_c_l_u_d_e directive for the above script we
must provide bindings for all of its free identifiers.  The bindings are
given in braces following the pathname (and before the aliases, if any).
Thus:-

	%_i_n_c_l_u_d_e "matrices" {elem==num; zero=0; mult=*; add=+; }

In  the  scope  of  the  script  containing  the  above  directive   the
identifiers   `matmult'   and   `addmult'  will  be  available  at  type
[[num]]->[[num]]->[[num]] and will behave as if  their  definitions  had
been  written  using  0, (+), (*) in place of the identifiers zero, add,
mult.

The order in which the bindings are given is immaterial (it need not  be
the  order in which the identifiers occurred in the %_f_r_e_e directive) but
a binding must be given  for  each  free  identifier  of  the  %included
script.   Note that the binding for a type is given using `==' and for a
value using `='.  If the types of all the bindings (taken together)  are
not  consistent  with the information given in the free directive of the
%included script, or if any required binding is  missing,  the  compiler
will reject the %_i_n_c_l_u_d_e directive as incorrect.

The main advantage of a parametrised script is that  different  bindings
may  be  given  for  its  free  identifiers on different occasions.  For
example the  same  script  "matrices"  may  be  invoked  with  different
bindings  to  provide a definition of matrix addition and multiplication
over matrices with elements of type bool.  Thus:-

	%_i_n_c_l_u_d_e "matrices" {elem==bool; zero=False; mult=&; add=\/; }

It is even possible to %_i_n_c_l_u_d_e the same parametrised  script  twice  in
the  same  scope  (presumably  with  different  bindings  for  the  free
identifiers) but in this case it will be be necessary to alias apart the
two  sets of exported identifiers to avoid a nameclash.  So we might add
`b_matadd/matadd b_matmult/matmult' to the above directive  if  it  were
being used in the same script as the previous one.

_M_i_s_c_e_l_l_a_n_e_o_u_s_ _p_o_i_n_t_s

By default the identifiers declared %_f_r_e_e in a parametrised  script  are
not  exported  from  the  script.   As  always this can be overridden by
explicitly listing them in an %_e_x_p_o_r_t directive.

Free typenames of non-zero arity are declared in the following style.

	%_f_r_e_e { stack * :: _t_y_p_e
		table * ** :: _t_y_p_e
		...
	      }

The corresponding bindings could be as follows

	%_i_n_c_l_u_d_e ... {stack * == [*]; table * ** == [(*,**)]; ... }

When a parametrised script exports a  locally  created  typename  (other
than  a synonym type), each instantiation of the script by a %_i_n_c_l_u_d_e is
deemed to create a NEW type (this is relevant to deciding whether or not
two  types are the same for the purpose of readopting a type orphan, see
previous manual section).  This is because the compiler assumes that  an
abstract  or  algebraic  type  defined  in a parametrised script will in
general have an internal structure that depends on the free identifiers.

Finally  note  that  the  bindings  for  the  free  identifiers   of   a
parametrised  script  must  always  be  given  EXPLICITLY.   For example
suppose we wish to %_i_n_c_l_u_d_e the file  "matrices"  in  a  script  already
containing  a  type  called  `elem'  over  which  we intend to do matrix
multiplication.  We must write

	%_i_n_c_l_u_d_e "matrices" {elem==elem; etc. }

The binding `elem==elem' is not redundant, nor is it cyclic, because the
two  `elem's  involved refer to two different scopes (on the left of the
binding, that of the includee, and on  the  right  that  of  the  script
containing the directive).