Search code examples
ocamlffireasonbucklescript

How to bind a whole module as a function?


I'm playing with reason, and I wanted to try to do the FFI for debug in order to learn. I have this code

module Instance = {
  type t;
  external t : t = "" [@@bs.module];
};

module Debug = {
  type t;
  external createDebug : string => Instance.t = "debug" [@@bs.module];
};

and I'm trying to use it like this

open Debug;    
let instance = Debug.createDebug "app";
instance "Hello World !!!";

but I get the following error

Error: This expression has type Debug.Instance.t
       This is not a function; it cannot be applied.

Wasn't instance supposed to be bind to a function? I also tried with

module Instance = {
  type t;
  external write : string => unit = "" [@@bs.send];
};

and

open Debug;    
let instance = Debug.createDebug "app";    
instance.write "Hello World !!!";

but I get

Error: Unbound record field write

What am I missing?


Solution

  • The createDebug function, according to your declaration, returns a value of type Instance.t. It is an abstract value, in a sense that nothing is known about its implementation, and you can only use it via its interface. The interface of a type is, basically, all values (functions) that allow you to manipulate a value of this type. In your case, we can find only two such values - the Instance.t value and Debug.createDebug function. Both can be used, according to your own declarations, to create such value. No functions are provided to use it.

    Probably, you have some misunderstanding of what module is. It is not an object per se, but rather a namespace. It is like a file in file.

    Your second example justifies that you're thinking of modules, as they are a sort of runtime objects or records. But, they are just static structures that are used to organize big programs into hierarchical namespaces.

    What you're trying to use is actually a record:

    type debug = { write : string => unit }
    
    let create_debug service => {
      write: fun msg => print_endline (service ^ ": " ^ msg)
    }
    
    let debug = create_debug "server"
    debug.write "started"
    

    Will yield:

    server: started