30 秒でわかる
A Jane Street speaker demonstrates the experimental include functor syntax developed in its OCaml compiler branch and proposed for upstreaming. Starting with an array-mapping interface, he builds a functor that supplies derived operations, shows the conventional wrapper-module approach, and replaces it with the new syntax.
- 1A mappable interfaceThe interface provides map and iter along with mapi and iteri, which also pass a key. An array implementation uses integer keys.
- 2Reverse traversalA reverse-array implementation handles the empty array and visits elements from the end. Traversal order matters when the supplied function has side effects.
- 3Derive the remaining operationsMap and iter can be built from mapi and iteri by ignoring the key, so a reusable functor can implement the common pattern.
- 4The wrapper-module boilerplateThe conventional approach puts the minimal definitions in a module, includes it, and includes the result of applying the functor to it.
- 5Include functorThe proposed syntax applies the functor using preceding definitions in the current module, avoiding the explicit wrapper and extra includes.
ポイント
- A module interface can expose convenient functions that are derived from a smaller set of core operations.
- In the example, map and iter can be defined from mapi and iteri by ignoring the key argument.
- A functor can package those derived definitions for reuse across modules.
- The conventional approach wraps existing definitions in a module and includes both it and the functor result.
- The proposed include functor syntax applies a functor to preceding module definitions without that explicit wrapper.
チャプターごとに整えた全文を読む
A proposed module convenience
The speaker introduces include functor, developed in Jane Street's compiler branch and being considered for upstreaming. A Mappable signature illustrates the repeated implementation pattern.
I want to introduce include functor, a feature developed in Jane Street's branch of the OCaml compiler that we are working to upstream. It simplifies a common pattern: writing the core of a module and using the same reusable logic to fill in the rest. The compiler used in the demonstration is linked in the video description.

Consider a module type Mappable with a data type, a key, and four operations: map and iter, plus mapi and iteri, whose functions also receive the key. An array can implement this interface straightforwardly: its key is an int, its data type is an array, and the four functions can use the corresponding array operations.
Reverse arrays and derived functions
A reverse implementation defines indexed operations from the last element to the first. The ordinary operations can be derived by ignoring the index.
Now suppose we want another array module that traverses from back to front. The order matters when an iteration function has side effects. The key and data type remain the same, but mapi works backwards: it handles an empty array separately, applies the function to the last element to initialize the result, and then fills the remaining positions down to zero.

The reverse iteri is simpler: it uses a backwards for loop. But I don't want to write map and iter again. They can be derived from mapi and iteri by ignoring the extra key argument, and the same pattern applies whenever we implement Mappable. We could still provide a specialized implementation when efficiency calls for it.
A reusable functor and its boilerplate
The signature is split into a minimal interface and additional operations. Applying a functor conventionally requires a wrapper module and explicit includes.
A functor can package the common derivation. First I split the interface into Mappable_minimal, containing the types and indexed operations, and the full Mappable interface, which includes that minimal part and adds map and iter. The functor Make_map_iter takes a module M matching Mappable_minimal.
Inside Make_map_iter, map calls M.mapi with a function that ignores the first argument and otherwise applies the supplied function. Iter does the same with M.iteri. The compiler infers the expected signature, so we now have a reusable way to produce the two ordinary operations.
Applying that functor to the reverse-array definitions is awkward in the conventional syntax. I wrap those definitions in a module M, include M, and include Make_map_iter(M). This works, but it requires the extra wrapper and explicit inclusion; without an enclosing signature, M itself would also remain visible.

Using include functor
The new syntax applies the functor to prior definitions in the current module and includes the result. The speaker briefly notes that it also works in module types.
Include functor removes that wrapper. After writing the core definitions directly in the module, I write include functor Make_map_iter. Conceptually, it applies the functor to the definitions already present in the module and includes the result. I can therefore define only the core functionality and get the rest without repeating the extra module and includes.

The syntax also works in module types, where it includes the functor's module type, though that is less common than the implementation example. The documentation has more detail on that use.
同じチャンネルの記事
1:48:29EN
1:36:37EN
1:05:45EN
1:25:00EN
1:16:29EN
27:39EN