Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the binding of the functor result with a new module name required to call nested functor of initial functor?

Tags:

functor

ocaml

I have:

module Functor(M : sig end) = struct
  module NestedFunctor(M : sig end) = struct
  end 
end

This code is valid:

module V = Functor(struct end)
module W = V.NestedFunctor(struct end)

But this is invalid:

module M = Functor(struct end).NestedFunctor(struct end)
                          (*  ^ Error: Syntax error *)

As I understand, a functor is a relation between a set of input modules and a set of possible output modules. But this example confuses my understanding. Why is the binding of the functor result with a new module name required to call nested functor of initial functor?

My compiler version = 4.01.0


I'm new to OCaml. When I found functors I imagined something as

Engine.MakeRunnerFor(ObservationStation
                       .Observe(Matrix)
                       .With(Printer))

I thought it is a good tool for the human-friendly architecture notation. Then I was disappointed. Of course, this is a syntax error and I understand that. But I think this restriction inflates grammar and makes it less intuitive. And my "Why?" in the main question is in the context of the concept of language.

like image 799
Valentine Zakharenko Avatar asked Aug 02 '14 06:08

Valentine Zakharenko


1 Answers

While I don't believe that this restriction is strictly necessary, it is probably motivated by certain limitations in OCaml's module type system. Without going into too much technical detail, OCaml requires all intermediate module types to be expressible as syntactic signatures. But with functors, that sometimes isn't possible. For example, consider:

module Functor(X : sig end) = struct
  type t = T of int
  module Nested(Y : sig end) = struct let x = T 5 end 
end

Given this definition, the type of the functor Functor(struct end).Nested can't be expressed in OCaml syntax. It would need to be something like

functor(Y : sig end) -> sig val x : Functor(struct end).t end  (* not legal OCaml! *)

but Functor(struct end).t isn't a valid type expression in OCaml, for reasons that are rather technical (in short, allowing a type like that would make deciding what types are equal -- as necessary during type checking -- much more involved).

Naming intermediate modules often avoids this dilemma. Given

module A = Functor(struct end)

the functor A.Nested has type

functor(Y : sig end) -> sig val x : A.t end

by referring to the named intermediate result A.

like image 187
Andreas Rossberg Avatar answered Nov 07 '22 10:11

Andreas Rossberg