@@ -133,6 +133,89 @@ defined :ref:`above <library-modules>`:
133133 This defines an explicit module named ``M ``. The body of this module defines
134134the class ``OneTwo ``.
135135
136+ .. _parameterised-modules :
137+
138+ Parameterised modules
139+ =====================
140+
141+ Parameterised modules are QL's approach to generic programming.
142+ Similar to explicit modules, parameterised modules are defined within other modules using the keywork ``module ``.
143+ In addition to the module name, parameterised modules define one or more parameters between the name and the module body.
144+
145+ For example, consider the module ``ApplyFooThenBar ``, which takes two predicate parameters and defines a new predicate
146+ that applies them one after the other:
147+
148+ .. code-block :: ql
149+
150+ module ApplyFooThenBar<transformer/1 foo, transformer/1 bar> {
151+ bindingset[x]
152+ int apply(int x) {
153+ result = bar(foo(x))
154+ }
155+ }
156+
157+ Parameterised modules cannot be directly referenced.
158+ Instead, they are instantiated with arguments passed between ``< `` and ``> ``.
159+ Instantiated parameterised modules can be used as a module expression, identical to explicit module references.
160+
161+ For example, we can instantiate ``ApplyFooThenBar `` with two identical arguments ``increment ``, creating a module
162+ containing a predicate that adds 2:
163+
164+ .. code-block :: ql
165+
166+ bindingset[result] bindingset[x]
167+ int increment(int x) { result = x + 1 }
168+
169+ module IncrementTwice = ApplyFooThenBar<increment/1, increment/1>;
170+
171+ select IncrementTwice::apply(40) // 42
172+
173+ The parameters of a parameterised module are (meta-)typed with :ref: `signatures <signatures >`.
174+
175+ For example, in the previous two snippets, we relied on the predicate signature ``transformer ``:
176+
177+ .. code-block :: ql
178+
179+ bindingset[x]
180+ signature int transformer(int x);
181+
182+ The instantiation of parameterised modules is applicative, meaning that repeated instantiation of a module using
183+ identical arguments results in the same object. This is particularly relevant for type definitions inside parameterised
184+ modules as :ref: `classes <classes >` or via :ref: `newtype <algebraic-datatypes >`.
185+
186+ For example, the following generates an error for the second call to ``foo ``, but not for the first:
187+
188+ .. code-block :: ql
189+
190+ bindingset[this]
191+ signature class TSig;
192+
193+ module M<TSig T> {
194+ newtype A = B() or C()
195+ }
196+
197+ string foo(M<int>::A a) { ... }
198+
199+ select foo(M<int>::B()), // valid: repeated identical instantiation of M does not duplicate A, B, C
200+ foo(M<float>::B()) // ERROR: M<float>::B is not compatible with M<int>::A
201+
202+ Module parameters are dependently typed, meaning that signature expressions in parameter definitions can reference
203+ preceding parameters.
204+
205+ For example, we can declare the signature for ``T2 `` dependent on ``T1 ``, enforcing a subtyping relationship
206+ between the two parameters:
207+
208+ .. code-block :: ql
209+
210+ signature class TSig;
211+
212+ module Extends<TSig T> { signature class Type extends T; }
213+
214+ module ParameterisedModule<TSig T1, Extends<T1>::Type T2> { ... }
215+
216+ Dependently typed parameters are particularly useful in combination with
217+ :ref: `parameterised module signatures <parameterised-module-signatures >`.
218+
136219.. _module-bodies :
137220
138221Module bodies
0 commit comments