-
Notifications
You must be signed in to change notification settings - Fork 0
/
Modules
467 lines (340 loc) · 15.3 KB
/
Modules
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
[[tags: manual]]
[[toc:]]
=== Modules
To allow control over visible bindings and to organize code in namespaces,
a module system is available. A ''module''
defines a set of toplevel expressions that are initially evaluated in
an empty syntactical environment. By ''importing'' other modules,
exported value- and syntax-bindings are made visible inside the
environment of the module that imports them.
Note that modules are purely syntactical - they do not change the
control flow or delay the execution of the contained toplevel
forms. The body of a module is executed at load-time, when code is
loaded or imported, just like normal
toplevel expressions. Exported syntax-definitions are compiled as
well, and can be accessed in interpreted or compiled code by loading
and importing the compiled file that contains the module.
Imported toplevel bindings are mutable and can be assigned
(with {{set!}}), any modifications
to these will change the global value and will be visible to other
modules that export or import the same toplevel binding.
A module is initially empty (has no visible bindings with the exception
of {{import}} and {{cond-expand}}). You must at least
import the {{scheme}} module to do anything useful. To access any
of the non-standard macros and procedures, import the {{(chicken base)}}
module.
CHICKEN's module system has the following features:
* Separation of compile/expansion-time and run-time code is provided, which allows cross compilation
* Supports batch-compilation of separate compilation units
* Imports can be lexically scoped
* Parameterized modules are supported
At toplevel and outside of a module, the initially available bindings
are everything that is exported from the [[Module scheme|scheme]],
[[Module (chicken base)|(chicken base)]] and
[[Module (chicken syntax)|(chicken syntax)]] modules.
==== module
<macro>(module NAME (EXPORT ...) BODY ...)</macro>
<macro>(module NAME (EXPORT ...) FILENAME)</macro>
<macro>(module NAME * BODY ...)</macro>
<macro>(module NAME = (FUNCTORNAME MODULENAME1 ...))</macro>
<macro>(module NAME = FUNCTORNAME BODY ...)</macro>
Defines a module with the name {{NAME}}, a set of exported bindings and
a contained sequence of toplevel expressions that are evaluated in an
empty syntactical environment.
{{NAME}} and {{FUNCTORNAME}} should be symbols or lists of symbols and
integers, where {{(foo bar baz)}} is equivalent to {{foo.bar.baz}}.
{{(EXPORT ...)}} should be an export-specification which holds a list
of identifiers to be exported from the module and which should be
visible when imported into another module or the toplevel
environment. {{EXPORT}} may have any of the following forms:
{{IDENTIFIER}} names a value- or syntax binding to be exported.
{{(IDENTIFIER1 ...)}} or {{(syntax: IDENTIFIER1 ...)}} exports
{{IDENTIFIER1}} (which should name a macro) and also arranges for the
remaining identifiers in the list to be visible as value bindings in the expansion of
the macro (this is a hint to the module expander to export bindings
referenced by syntax-definitions which make use of them, but which
would normally be internal to the module - which gives more
opportunities for optimization).
{{(interface: INTERFACENAME)}} adds all exports defined for the given
interface to be added to the list of exported identifiers of this
module.
As a special case, specifying {{*}} instead of an export-list will
export all definitions. As another special case, the export-list may
be a symbol naming an interface.
When the {{BODY}} consists of a single string, it is treated
like {{(include FILENAME)}}.
{{(module NAME = (FUNCTORNAME MODULENAME1 ...))}} instantiates
a ''functor'' (see below for information about functors).
{{(module NAME = FUNCTORNAME BODY ...)}} is a special form of
''functor instantiation'' where the {{BODY}} implements a module
satisfying a single functor argument to {{FUNCTORNAME}}.
Nested modules, modules not at toplevel (i.e. local modules) or
mutually recursive modules are not supported.
When compiled, the module information, including exported syntax
is stored in the generated binary and available when loading
it into interpreted or compiled code. Note that this is different
to normal syntax (outside of module declarations), which are normally
not exported from compiled code.
Note that the module system is only a device for controlling the
mapping of identifiers to value or syntax bindings. Modules do not
instantiate separate environments that contain their own bindings, as
do many other module systems. Redefinition or assignment of value or
syntax bindings will modify the original, imported definition.
Syntax expansions may result in module-definitions, but must be
at toplevel.
==== export
<macro>(export EXPORT ...)</macro>
Allows augmenting module-exports from inside the module-body.
{{EXPORT}} is if the same form as an export-specifier in a
{{module}} export list. An export must precede its first occurrence
(either use or definition).
If used outside of a module, then this form does nothing.
==== import
<macro>(import IMPORT ...)</macro>
Imports module bindings into the current syntactical environment.
The visibility of any imported bindings is limited to the current
module, if used inside a module-definition, or to the current
compilation unit, if compiled and used outside of a module.
Importing a module will also load or link its associated library when
needed.
{{IMPORT}} may be a module name or an ''import specifier'', where a
module name is either a symbol or a list of symbols and integers.
An {{IMPORT}} defines a set of bindings that are to be made visible
in the current scope.
===== only
[import specifier] (only IMPORT IDENTIFIER ...)
Only import the listed value- or syntax bindings from the set given
by {{IMPORT}}.
===== except
[import specifier] (except IMPORT IDENTIFIER ...)
Remove the listed identifiers from the import-set defined by {{IMPORT}}.
===== rename
[import specifier] (rename IMPORT (OLD1 NEW1) ...)
Renames identifiers imported from {{IMPORT}}.
===== prefix
[import specifier] (prefix IMPORT SYMBOL)
Prefixes all imported identifiers with {{SYMBOL}}.
==== import-syntax
<macro>(import-syntax IMPORT ...)</macro>
Similar to {{import}} but only import syntactic definitions such as
macros, as well as identifiers, but does not load or link the library
containing the module.
==== import-for-syntax
<macro>(import-for-syntax IMPORT ...)</macro>
Similar to {{import}}, but imports exported bindings of a module into
the environment in which macro transformers are evaluated.
Note: currently this isn't fully correct - value bindings are still
imported into the normal environment because a separate import
environment for syntax has not been implemented (syntactic bindings
are kept separate correctly).
==== import-syntax-for-syntax
<macro>(import-syntax-for-syntax IMPORT ...)</macro>
Combination of {{import-syntax}} and {{import-for-syntax}}. Loads
syntactic definitions and valinside the environment in which macro
transformers are evaluated but do not load the associated library.
==== reexport
<macro>(reexport IMPORT ...)</macro>
Imports {{IMPORT ...}} and automatically exports all imported identifiers.
This can be used to build ''compound modules'': modules that just extend
other modules:
<enscript hightlight=scheme>
(module r4rs ()
(import scheme (chicken module))
(reexport
(except scheme
dynamic-wind values call-with-values eval scheme-report-environment
null-environment interaction-environment)))
</enscript>
=== define-interface
<macro>(define-interface INTERFACENAME (EXPORT ...))</macro>
Defines an ''interface'', a group of exports that can be used in
module-definitions using the {{(interface: INTERFACE)}} syntax.
See the definition of {{module}} above for an explanation of
{{EXPORT}} specifications.
Interface names use a distinct global namespace. Interfaces defined
inside modules are not visible outside of the module body.
=== import libraries
''import libraries'' allow the syntactical (compile-time)
and run-time parts of a compiled module to be separated into a normal
compiled file and a shared library that only contains macro definitions
and module information. This reduces the size of executables and
simplifies compiling code that uses modules for a different architecture
than the machine the compiler is executing on (i.e. "cross" compilation).
By using the {{emit-import-library}} compiler-option or declaration,
a separate file is generated that only contains syntactical information
(including macros) for a module. {{import}} will automatically find and
load an import library for a currently unknown module, if the import-
library is either in the extension repository or the current include
path. Interpreted code
can simply load the import library to make the module-definition
available. Syntax-support definitions defined with {{define-for-syntax}}
and expansion-time expressions of the form {{(begin-for-syntax ...)}}
will be added to import libraries to make them available for exported
syntax. Note that these definitions will ruthlessly pollute the
toplevel namespace and so they should be used sparingly.
=== Predefined modules
Import libraries for the following modules are initially
available outside of a module:
[module] scheme
[module] (chicken base)
[module] (chicken syntax)
Every other module needs to be imported explicitly to have access to
its exported identifiers.
=== Examples of using modules
Here is a silly little test module to demonstrate how modules
are defined and used:
;; hello.scm
(module test (hello greet)
(import scheme)
(define-syntax greet
(syntax-rules ()
((_ whom)
(begin
(display "Hello, ")
(display whom)
(display " !\n") ) ) ) )
(define (hello)
(greet "world") ) )
The module {{test}} exports one value ({{hello}}) and one syntax
binding ({{greet}}). To use it in {{csi}}, the interpreter,
simply load and import it:
#;1> ,l hello.scm
; loading hello.scm ...
; loading /usr/local/lib/chicken/4/scheme.import.so ...
#;1> (import test)
#;2> (hello)
Hello, world !
#;3> (greet "you")
Hello, you !
The module can easily be compiled
% csc -s hello.scm
and used in an identical manner:
#;1> ,l hello.so
; loading hello.so ...
#;1> (import test)
#;2> (hello)
Hello, world !
#;3> (greet "you")
Hello, you !
If you want to keep macro-definitions in a separate file, use import
libraries:
% csc -s hello.scm -j test
% csc -s test.import.scm
#;1> ,l hello.so
; loading hello.so ...
#;1> (import test)
; loading ./test.import.so ...
#;2> (hello)
Hello, world !
#;3> (greet "you")
Hello, you !
If an import library (compiled or in source-form) is located
somewhere in the extensions-repository or include path, it
is automatically loaded on import. Otherwise you have to
load it manually:
#;1> ,l hello.so
; loading hello.so ...
#;1> ,l test.import.so
; loading test.import.so ...
#;1> (import test)
#;2>
Note that you must use import libraries if you compile code
that depends on other modules. The compiler will not execute
the modules that are referred to by compiled code, and thus
the binding information and exported syntax of the former
must be available separately.
=== Functors
A ''functor'' is a higher-order module that can be parameterized with
other modules. A functor defines the body of a module for a set of
argument modules and can be instantiated with concrete module names
specializing the code contained in the functor. This is best explained
with a silly and pointless example:
<enscript highlight=scheme>
(functor (squaring-functor (M (multiply))) (square)
(import scheme M)
(define (square x) (multiply x x)))
</enscript>
This defines a generic "squaring" operation that uses {{multiply}}, a
procedure (or macro!) exported by the as-yet-unknown module {{M}}. Now
let's instantiate the functor for a specific input module:
<enscript highlight=scheme>
(module nums (multiply)
(import scheme)
(define (multiply x y) (* x y)))
(module number-squarer = (squaring-functor nums))
(import number-squarer)
(square 3) ===> 9
</enscript>
We can easily instantiate the functor for other inputs:
<enscript highlight=scheme>
(module stars (multiply)
(import scheme)
(define (list-tabulate n f)
(let loop ((i 0))
(if (= i n)
'()
(cons (f i) (loop (+ i 1))))))
(define (multiply x y)
(list-tabulate x (lambda _ (list-tabulate y (lambda _ '*))))))
(module star-squarer = (squaring-functor stars))
(import star-squarer)
(square 3) ===> ((* * *)
(* * *)
(* * *))
</enscript>
So whenever you have a generic algorithm it can be packaged into a
functor and specialized for specific input modules. The instantiation
will check that the argument modules match the required signature,
{{(multiply)}} in the case above. The argument module must export at
least the signature given in the functor definition. You can use
{{define-interface}} to reduce typing and give a more meaningful name
to a set of exports.
The general syntax of a functor definition looks like this:
<syntax>(functor (FUNCTORNAME (ARGUMENTMODULE1 EXPORTS1) ...) FUNCTOREXPORTS BODY)</syntax>
Defines a "functor", a parameterized module.
This functor definition does not generate any code. This is done
by ''instantiating'' the functor for specific input modules:
<enscript highlight=scheme>
(module MODULENAME = (FUNCTORNAME MODULENAME1 ...))
</enscript>
Inside {{BODY}}, references to {{ARGUMENTMODULE}} will be replaced by
the corresponding {{MODULENAME}} argument. The instantiation expands
into the complete functor-code {{BODY}} and as such can be considered
a particular sort of macro-expansion. Note that there is no
requirement that a specific export of an argument-module must be
syntax or non-syntax - it can be syntax in one instantiation and a
procedure definition in another.
{{ARGUMENTMODULE}} may also be a list of the form {{(ALIAS DEFAULT)}}
to allow specifying a default- or optional functor argument in case
the instanation doesn't provide one. Optional functor
arguments may only be followed by non-optional functor arguments.
The common case of using a functor with a single argument module
that is not used elsewhere can be expressed in the following way:
<enscript highlight=scheme>
(module NAME = FUNCTORNAME BODY ...)
</enscript>
which is the same as
<enscript highlight=scheme>
(begin
(module _NAME * BODY ...)
(module NAME = (FUNCTORNAME _NAME)))
</enscript>
Since functors exist at compile time, they can be stored in
import-libraries via {{-emit-import-library FUNCTORNAME}} or
{{-emit-all-import-libraries}} (see [[Using the compiler]] for more
information about this). That allows you to import functors for later
instantiation. Internally, a functor-definition also defines a module
with the same name, but importing this module has no effect. It also
has no runtime code, so it is sufficient to merely {{import}} it (as
opposed to using {{require-extension}} or one of its variants, which
also loads the run-time part of a module).
Note that functor-instantiation creates a complete copy of the
functor body.
=== current-module
<macro>(current-module)</macro>
This will expand to a symbol which matches the current module's name
when used inside a module. If not inside a module (i.e., at
toplevel), this expands to {{#f}}.
---
Previous: [[Interface to external functions and variables]]
Next: [[Types]]