summaryrefslogtreecommitdiff
path: root/miralib/manual/27/3
blob: 5891ed276dada94d6c114728cb836f38e9ebe661 (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
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
_E_x_p_l_a_n_a_t_i_o_n_ _o_f_ _l_i_b_r_a_r_y_ _d_i_r_e_c_t_i_v_e_s

The three directives  %_i_n_c_l_u_d_e  %_e_x_p_o_r_t  %_f_r_e_e  constitute  the  Miranda
library  mechanism,  which  controls  the sharing of identifiers between
separately compiled scripts.   The  %_f_r_e_e  directive  is  covered  in  a
separate manual entry and will not be discussed further here.
------------------------------------------------------------------------

%_i_n_c_l_u_d_e "file"

The presence of this directive, anywhere in a Miranda script, causes all
the  identifiers  exported from the Miranda script "file" to be in scope
in the containing script.  Note that "file" should  be  the  name  of  a
Miranda source file (by convention these all have names ending in `.m').

The following conventions apply to all filenames in library directives:
 1) A fileid can be an arbitrary UNIX pathname
 2) If the fileid given does not end in `.m' this is added.
 3)  If  the  fileid  is  surrounded by angle brackets instead of string
quotes it is  assumed  to  be  a  pathname  relative  to  the  `miralib'
directory,  otherwise it is taken to be relative to the directory of the
script in which the directive occurs.  (Examples, "pig"  means  "pig.m",
<stdenv> means "/usr/lib/miralib/stdenv.m")

In addition (if you are using Berkeley UNIX or  a  derivative)  the  `~'
convention  of  the  cshell  may be used to abbreviate home directories.
That is `~' abbreviates your own home directory, and  ~jack  abbreviates
jack's home directory, at the front of any pathname.

The file mentioned in a  %_i_n_c_l_u_d_e  directive  must  contain  a  CORRECT,
CLOSED  Miranda script.  (That is it must have no syntax or type errors,
and no undefined names.) An attempt to %_i_n_c_l_u_d_e a  file  which  violates
these  conditions  will be rejected by the compiler as a syntax error in
the script containing the %_i_n_c_l_u_d_e statement.

It is also illegal to %_i_n_c_l_u_d_e a script which causes nameclashes, either
against  top-level identifiers of the including script or those of other
%_i_n_c_l_u_d_e directives in the script.

The effect of an %_i_n_c_l_u_d_e directive can be modified by following it with
one  or  more  aliases  (which  are  used  to remove nameclashes between
identifiers exported from the included script and those of the  current
script  or  of  other  %_i_n_c_l_u_d_e  files).   There are two forms of alias,
`new/old' which  renames  and  `-old'  which  suppresses  an  identifier
altogether.

For example suppose we wish to include the file "mike" but  it  contains
two  identifiers,  f  and  g say, which clash with top-level bindings of
these identifiers in the current script.  We  wish  to  use  the  "mike"
definition  of  `f',  but  his  `g'  is  of  no interest.  The following
directive could be used.

%_i_n_c_l_u_d_e "mike" -g mike_f/f

Any other identifiers exported from "mike", not  specifically  mentioned
in the aliases, will be accepted unchanged.

It is permitted to alias typenames, and constructors (say `NEW/OLD') but
typenames and constructors cannot be  suppressed  by  a  `-name'  alias.
Note  that  if you alias one or more of the constructors of an algebraic
data type the behaviour of `_s_h_o_w'  on  objects  of  that  type  will  be
modified in the appropriate way.

A file which has been %included may itself contain %_i_n_c_l_u_d_e  directives,
and  so  on, to any reasonable depth.  A (directly or indirectly) cyclic
%_i_n_c_l_u_d_e is not permitted, however.

The  `?identifier'  command  can  be  used to find the ultimate place of
definition of an imported identifier.  When aliasing has taken place the
`?identifier'  command  will give both the current and the original name
of an  aliased  identifier.   If  your  installed  editor  is  `vi'  the
`??identifier'  command  will  open  the  appropriate source file at the
definition  of  the  identifier.   (There  is  also  a  command   `/find
identifier'  which  is  like  `?identifier'  but will recognise an alias
under its original name.)

Every script behaves as though it contained the directive
	%_i_n_c_l_u_d_e <stdenv>

It is therefore illegal to %_i_n_c_l_u_d_e the standard environment explicitly,
as  this  will  lead  to  huge number of name clashes (because it is now
present twice).  As a consequence there is currently no way of  aliasing
or  suppressing  the  names  in the standard environment.  (This will be
fixed in the  future  by  providing  a  directive  for  suppressing  the
implicit inclusion of <stdenv>.)
------------------------------------------------------------------------

%_e_x_p_o_r_t parts

Any (correct, closed) Miranda script can be %included in another  script
(there  is  no notion of a "module" as something with a different syntax
from an ordinary script).  By default the names exported from  a  script
are all those defined in it, at top level, but none of those acquired by
a %_i_n_c_l_u_d_e of another file.  This behaviour can be modified  (either  to
export  more  or  to  export less than the default) by placing a %_e_x_p_o_r_t
directive in the script, specifying a list of `parts' to be exported  to
an including file.

The presence of a %_e_x_p_o_r_t directive in a script has  no  effect  on  its
behaviour  when  it  is  the current script of a Miranda session - it is
effective only when the script is %included in another.   A  script  may
contain  at  most  one  %_e_x_p_o_r_t  directive.  This can be anywhere in the
script, but to avoid nasty surprises it is advisable to  place  it  near
the top.

Each `part' listed in the export directive must be one of the following:
 identifier (variable or typename)
 fileid (in quotes, conventions as described above)
 the symbol `+'
 -identifier

Notice  that  constructors need not (and cannot) be listed explicitly in
an %_e_x_p_o_r_t  directive  -  if  you  export  an  algebraic  typename,  its
constructors  are AUTOMATICALLY exported along with it.  The consequence
of this is that you cannot use %_e_x_p_o_r_t to create an abstract data  type,
by  "hiding information" about how an algebraic type was formed.  If you
want to create an abstract data type you must use the _a_b_s_t_y_p_e  mechanism
- see separate manual entry.

If a fileid is present in the export list, this must be the  name  of  a
file  which is %included in the exporting script, and the effect is that
all the bindings acquired by that %_i_n_c_l_u_d_e  statement  (as  modified  by
aliases  if  present)  are re-exported.  Allowing fileid's in the export
list is merely a piece of shorthand, which can be used to avoid  writing
out long lists of names.

The symbol `+' is allowed in an export list as an abbreviation  for  all
the top-level identifiers defined in the current script.

The default %_e_x_p_o_r_t directive (i.e.  that which is assumed if no %_e_x_p_o_r_t
statement is present) is therefore
	%_e_x_p_o_r_t +
This  will  export  all the top-level identifiers of the current script,
but not those acquired by %_i_n_c_l_u_d_e directives.

Finally, the notation `-identifier' is allowed  in  an  export  list  to
indicate that this identifier NOT to be exported.  This is useful if you
have used a fileid or the symbol `+' to abbreviate a list of names,  and
wish to subtract some of these names from the final export list.

An example - the following export statement exports  all  the  top-level
identifiers of the current script, except `flooby'.
	%_e_x_p_o_r_t + -flooby

The order of appearance of  the  items  in  an  export  list  is  of  no
significance,  and repetitions are ignored.  A negative occurrence of an
identifier overrides any number of positive occurrences.

It  is possible to find out what names are exported from a given Miranda
script (or scripts) by calling, from UNIX, the command
 `mira -exports files' (the extension `.m' will be added  to  each  file
name if missing).  This will list (to stdout) for each file the exported
names together with their types.
------------------------------------------------------------------------

_S_o_m_e_ _e_x_a_m_p_l_e_s

(i) There are two scripts, called "liba.m" and "libb.m" say,  containing
useful  definitions.   For  convenience  we  wish to combine them into a
single larger library called say, "libc.m".  The following  text  inside
the file "libc.m" will accomplish this.

	%_e_x_p_o_r_t "liba" "libb"
	%_i_n_c_l_u_d_e "liba"
	%_i_n_c_l_u_d_e "libb"

You  will  notice  that  when  "libc.m" is compiled, this does NOT cause
recompilation  of  "liba.m"  and  "libb.m"  (see  section  on   separate
compilation  -  the  compiler  is able to create an object code file for
"libc.m", called "libc.x", by combining  "liba.x"  and  "libb.x"  in  an
appropriate  way).   This  economy in recompilation effort is one reason
why %_i_n_c_l_u_d_e is a better mechanism than the  simpler  textual  directive
%_i_n_s_e_r_t (see section on compiler directives).

We  could  if  we  wished  add  some  definitions  to "libc.m" - if the
corresponding names are added to the %_e_x_p_o_r_t  statement  these  bindings
will  then  be  exported  along  with those of the two sublibraries.  Of
course if we don't add the names of the locally defined objects  to  the
%_e_x_p_o_r_t  directive  they  will be `private definitions' of "libc.m", not
visible to includors.

Recall that if no  %_e_x_p_o_r_t  is  directive  is  present,  then  ONLY  the
immediate  definitions  (if  any)  of  "libc.m"  will be exported.  So a
script which contains only %_i_n_c_l_u_d_e directives and no %_e_x_p_o_r_t cannot  be
usefully %included in another script (it is however perfectly acceptable
as a current script).

(ii) [More technical - omit on first reading]
 Our second group of examples is chosen to bring out some  issues  which
arise  when  exporting  types  between  scripts.   Suppose  we  have the
following script, called "trees.m"
	
	tree * ::= NILT | NODE * (tree *) (tree *)
	reflect :: tree *->tree *
	reflect NILT = NILT
	reflect (NODE a x y) = NODE a(reflect y)(reflect x)

(a) If in another script we  write  `%_i_n_c_l_u_d_e  "trees"',  the  following
bindings  will  be  imported  -  tree NILT NODE reflect.  Now suppose we
modify the "trees.m" by placing in it the following directive - `%_e_x_p_o_r_t
reflect'.  When the modified "trees.m" script is included in another, we
will get the  following  error  message  from  the  compilation  of  the
including script:

	MISSING TYPENAME
	the following type is needed but has no name in this scope:
	'tree' of file "trees.m", needed by: reflect;
	typecheck cannot proceed - compilation abandoned

Explanation - it is illegal to export an identifier to a place where its
type, or any part of its type, is unknown.  In this  situation  we  call
reflect a `type-orphan' - it has lost one of its parents!

(b)  Readoption  of a type-orphan (a more subtle example).  Assuming the
"trees.m" script in  its  original  form  as  above,  we  construct  the
following file "treelib.m"

	%_e_x_p_o_r_t size
	%_i_n_c_l_u_d_e "trees"
	size :: tree *->num
	size NILT = 0
	size (NODE a x y) = 1+size x+size y

If  we  %_i_n_c_l_u_d_e  the  above  script in another as it stands, we will of
course get a missing typename diagnostic for `size' -  consider  however
the following script

	%_i_n_c_l_u_d_e "treelib"
	%_i_n_c_l_u_d_e "trees"
	... (etc)

Everything  is  now  ok,  because  a  name  for size's missing parent is
imported through another route (the  second  %_i_n_c_l_u_d_e  statement).   The
Miranda  compiler  recognises  the  `tree'  type  imported by the second
%_i_n_c_l_u_d_e as being the same one as that referred to  inside  "treelib.m",
because  it  originates  (albeit  via  different  routes)  from the SAME
SOURCEFILE.   A  `tree'  type  imported  from   a   different   original
sourcefile,  even  if  it  had  the same constructor names with the same
field types, would be recognised as a different type.

[Note: the Miranda compiler is always able to recognise  when  the  same
source  file  is  inherited  via  different  routes,  including in cases
involving files with multiple pathnames due to the presence of (hard  or
symblic) links.]

[Further  note:  the lexical directive %_i_n_s_e_r_t (see compiler directives)
should be regarded as making a _t_e_x_t_u_a_l_ _c_o_p_y of  the  material  from  the
inserted  file  into  the file containing the %_i_n_s_e_r_t directive - if the
text of a type definition (in ::= or abstype) is copied in this way, the
compiler  will  regard  the %_i_n_s_e_r_t as having created a new type in each
such case, not identical with that in the inserted file.]

(c) Last example (typeclash).  Finally note that that it is illegal  for
the  same  original  type  to be imported twice into the same scope even
under different names.  Consider the following script

	%_i_n_c_l_u_d_e "trees" shrub/tree Leaf/NILT Fork/NODE -reflect
	%_i_n_c_l_u_d_e "trees"
	... (etc)

The first %_i_n_c_l_u_d_e taken on its own is perfectly ok - we  have  imported
the `tree' type, and renamed everything in it by using aliases.  However
we have also inherited the `tree' type under its original name, via  the
second %_i_n_c_l_u_d_e.  The compiler will reject the script with the following
message:

	TYPECLASH - the following type is multiply named:
	'tree' of file "trees.m", as: shrub,tree;
	typecheck cannot proceed - compilation abandoned

The rule that a type can have at most one name in a given scope  applies
to both algebraic types and abstract types (it does not apply to synonym
types, because these are not `real' types but mere  macro's  -  you  can
have  any  number  of synonyms for `tree' in scope at the same time - as
long as the underlying `real' type has a unique name).

Typeclashes are illegal in Miranda in order to  preserve  the  following
two  principles.  (i) In any given scope, each possible type must have a
unique canonical form (obtained by expanding out synonyms, and  renaming
generic  type  variables  in  a  standard  way).   (ii) Each object of a
`printable type' must have,  in  any  given  scope,  a  unique  external
representation  (ruling  out  multiply  named  constructors).  The first
principle is necessary to the functioning of the typechecker, the second
is demanded by the requirement that the function `_s_h_o_w' be referentially
transparent.