[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Chicken-hackers] functors
From: |
Felix |
Subject: |
[Chicken-hackers] functors |
Date: |
Thu, 24 Mar 2011 06:22:19 -0400 (EDT) |
Hello!
For quite a while I thought about how to implement "functors",
i.e. modules that take modules as parameters. After several failed
attempts with macros that expand into modules I now tried a different
approach by directly integrating this into the core system. Tests pass
and things appear to work fine, but I'm unsure whether the approach is
sound or whether it s considered useful. This also adds a few
generalizations to the module system, and I present the concepts here
in case someone has suggestions or criticisms.
Interfaces:
It is possible to define /interfaces/ (named groups of exports),
for example:
(define-interface ARITHMETIC
(+ - * /))
(module foo (this that (interface: ARITHMETIC) the-other)
...)
The "export list" of a module may optionally be an interface name
so
(module bar ((interface: ARITHMETIC)) ...)
could also be written as
(module bar ARITHMETIC ...)
[This implies an interface may not be named "*"]
The syntax is a bit ugly, but I couldn't think of a better way, which
doesn't introduce ambiguity into the syntax. For symmetry, there is
now also "(syntax: SYNTAXIDENTIFIER [IMPLICITEXPORT ...])", equivalent
to "(SYNTAXIDENTIFIER [IMPLICITEXPORT ...])". This is not enforced in
the moment, but may be useful for documentation purposes.
Functors:
A /functor/ is a module that takes other modules as parameters,
binding the argument modules to temporary identifiers inside the body:
(functor (linear-search-functor (S FINITE-SET)) (search)
(import scheme S)
...)
Inside "linear-search-functor", "S" refers to some module that
satisfies the interface "SEQUENCE", that is, which exports at least
the identifiers defined in the interface. The general syntax is:
(functor (FUNCTORNAME (ARGUMENT1 EXPORTLIST1) ...) FUNCTOREXPORTS BODY ...)
One uses a functor by /instantiating/ it:
(module my-search = (linear-search-functor some-key-value-store))
(import my-search)
(search ...)
This will expand into a module definition containing the body of the
functor "linear-search-functor", and with imports of "S" redirected to
the module "some-key-value-store". This could be simply done by syntax
that expands into a module, but functor-instantiation will check that
the argument modules satisfy the required exports. Also, the functor
itself will be put into a module, so an import-library can be
generated and installed for it.
I'm not sure if simply substituting the functor body in the
instantiation is a problem - exccessive use may result in code bloat,
which means functors should be restricted to the part that is truly
specialized to the argument modules. Standard ML compilers IMHO
generate only a single functor body, but it is very difficult to find
much information about functor implementation, apart from a lot of
type-theoretic mumbo jumbo. Scheme48 apparently has higher-order
modules, but only hints at them in the manual. Another difference is
that an import may refer to a procedure in one instantiation and to
syntax in another one. Restricting this looks like a loss of
expressivity to me, so full functor-body substitution seems to be the
only option. On the other hand, this allows the body to compile to
heavily specialized code if the imports refer to syntax, low-level
intrinsics or those core library procedures that the compiler is able
to optimize well (or for which type-information is available in the
forthcoming type-driven "specialization" optimization which is
currently in the works). I have seen heavily optimized libraries once
or twice, which basically where just a macro parameterized with
primitive operations that expands into a set of procedure
definitions. I remember a really badass red-black tree implementation
by Marc Feeley, but can't recall where I found it. It was written in
this style and would be a perfect use case for a functor.
Anyway, that's it.
cheers,
felix
- [Chicken-hackers] functors,
Felix <=