%raw vs. @bs.module and weak polymorphism

This is just a question to better understand how the type system works: no direct practical application I’m trying to achieve. Sorry if my syntax is out of date, I haven’t switched to ReScript yet.

If I wrap the following JS:

let logPlain2 = (a, b) => console.log(a, JSON.stringify(b));

like this, in Util.re:

[@bs.module "./jsScratch"] external logPlain2: ('a, 'b) => unit = "logPlain2";

Then I can use it like this (where doc is a non-string type:

Util.logPlain2("x", "y");
Util.logPlain2("doc x", doc);

I think it doesn’t matter here, but the type of doc is defined like this in another module – the point is, it’s not a string, unlike “y”:

type t('w) = 'w;

But if I instead do this:

  let logPlain2: ('a, 'b) => unit = [%raw
    {|(a, b) => console.log(a, JSON.stringify(b))|}

Then I can’t do this:

  logPlain2("x", "y");
  logPlain2("doc x", doc);

I gather this is related to weak polymorphism, which I only partially understand. I do see why it rejects the last bit of code there (at least once it has decided that the type variables are weakly polymorphic).

So two questions actually:

  1. I assume that the version wrapped with [%raw ...] has a different type that the one wrapped with [@bs.module ...], but they appear to have the same type in their definitions. How do the types differ (I guess I should say type declarations rather than types perhaps)? Is the difference just that one is external?

  2. Is it possible to write a function that behaves like the [@bs.module ...]-wrapped one when using [%raw]?

1 Like

The thing is compiler does not think logPlain2 defined using %raw is a function, it treat it as a value, so it is not as polymorphic as you expect due to the impurity of the language.
You can achieve something similar as below:

 let logPlain2: ('a, 'b) => unit = (a,b) => {
    {|(a, b) => console.log(a, JSON.stringify(b))|}
  ] (a,b)
1 Like