The big migration thread for ReScript v11 (and uncurried mode)

I have couple questions on the default uncurried mode:

  1. With ReScript v11 rc4, my top-level project compiles fine with uncurried:true but there are a few external ReScript libraries that I use won’t. Is there a config that I can use to tell the compiler to use uncurried:false for external libraries?

  2. I understand the curried by default is discouraged going forward, but what is the unofficial escape hatch to compile a file in curried mode? I have been using:

@@uncurried
@@uncurried.swap

at the top of each .res that I want to do currying. Also, even with that, I need to explicitly put . in front of function parameter to make it curried.

Is this the right way to do it?

  1. Is function type definition affected by uncurried mode? ie:
type f = 'a => 'b

would f be type matched with both x => y and (. x) => y ?

Thanks,

This hasnt been my experience so far. looking at rescript-apollo-client i had to switch Belt.Array.map to Belt.Array.mapU to compile.

I am on a prerelase vscode plugin, not sure if thats new enough, but those tooltips were copy-paste from the editor.

Is there any difference between:

  let fn = (x, y, z) => x + y + z

  let fnA = fn(x, ...)
  let fnB = (y, z) => fn(x, y, z)

?

Any chance it’s from a namespaced / pinned dependency?
I recall there was something odd when not every dependency in a workspace repo had "uncurried" set to true explicitly, but not sure if that issue still exists.

Alternatively you could wrap it into a function: (item) => item->Belt.Array.map(fn)

If it could be possible to set dependencies to the uncurried mode that would help immensely with backwards compatibility.

The other place I struggle with dependencies is file extensions. It would also help to be able to override the file extension of specific dependencies.

1 Like

What are you talking about? If the compiled file extension, then as I know they inherit the file extension from the root bsconfig.

basically, it would be nice to use the file extension required in the dependency’s bsconfig instead of the root

Hi Yall
A following question from other threads:
Will explicit currying apply to Functors as well?
I cant say I hit it often, but when you dont fully saturate a functor, the warning is really something.

Thanks
A

1 Like

Hi !

I started the migration and the watch seems to doesn’t work when I have code error. Any idea ?
Just in case, here is one of my rescript.json file config :

{
  "$schema": "https://raw.githubusercontent.com/rescript-lang/rescript-compiler/master/docs/docson/build-schema.json",
  "name": "@colisweb/rescript-toolkit",
  "jsx": {
    "version": 4
  },
  "sources": [
    {
      "dir": "src",
      "subdirs": true
    },
    {
      "dir": "playground",
      "subdirs": true,
      "type": "dev"
    }
  ],
  "package-specs": [
    {
      "module": "es6-global",
      "in-source": false
    }
  ],
  "suffix": ".bs.js",
  "namespace": false,
  "uncurried": true,
  "bs-dependencies": [
    "@rescript/react",
    "reason-promise",
    "@greenlabs/ppx-spice",
    "rescript-classnames",
    "rescript-react-update",
    "@dck/restorative"
  ],
  "ppx-flags": [
    ["@greenlabs/ppx-spice/ppx", "-uncurried"],
    "lenses-ppx/ppx",
    "res-react-intl/ppx"
  ],
  "warnings": {
    "number": "-44-30-32",
    "error": "+5"
  },
  "bsc-flags": [
    "-bs-super-errors",
    "-bs-no-version-header",
    "-open Belt",
    "-open Cx"
  ]
}

It’s a regression of rc-4. I’ll fix it in the next version Watch mode is not working in `11.0.0-rc.4` · Issue #6435 · rescript-lang/rescript-compiler · GitHub.
As a solution you can try using rewatch.

3 Likes

Thanks for your fast reply !

I have some issues with Js.Dict.t and the uncurried mode. I’m trying to upgrade the code based on this coupled with @spice.

For reference, here is the implementation :

module MakeString = () => {
  module Id: {
    @spice
    type t
    module Dict: {
      type key = t
      @spice
      type t<'a>
      let get: (t<'a>, key) => option<'a>
      @set_index
      external set: (t<'a>, key, 'a) => unit = ""
      @val
      external keys: t<'a> => array<string> = "Object.keys"
      @obj /** Returns an empty dictionary. */
      external empty: unit => t<'a> = ""
      let unsafeDeleteKey: (t<string>, string) => unit
      let entries: t<'a> => array<(key, 'a)>
      let values: t<'a> => array<'a>
      let fromList: list<(key, 'a)> => t<'a>
      let fromArray: array<(key, 'a)> => t<'a>
      let map: ('a => 'b, t<'a>) => t<'b>
      let deleteKey: (t<'a>, key) => t<'a>
    }
  } = {
    @spice
    type t = string
    module Dict = {
      include Js.Dict

      let deleteKey: (t<'a>, string) => t<'a> = %raw("function (dict, key) {
  const newDict = Object.assign({},dict);
  delete newDict[key];
  return newDict;
}")
      let t_encode = (encoder, dict): Js.Json.t => Js.Json.Object(
        Js.Dict.map(a => encoder(a), dict),
      )

      let t_decode = (decoder, json) => {
        open Spice
        switch (json: Js.Json.t) {
        | Js.Json.Object(dict) =>
          dict
          ->Js.Dict.entries
          ->Belt.Array.reduce(Ok(Js.Dict.empty()), (acc, (key, value)) =>
            switch (acc, decoder(value)) {
            | (Error(_), _) => acc

            | (_, Error({path} as error)) => Error({...error, path: "." ++ (key ++ path)})

            | (Ok(prev), Ok(newVal)) =>
              let () = prev->Js.Dict.set(key, newVal)
              Ok(prev)
            }
          )
        | _ => Error({path: "", message: "Not a dict", value: json})
        }
      }
    }
  }

  @spice
  type t = Id.t

  module Dict = Id.Dict

  external make: string => t = "%identity"
  external toString: t => string = "%identity"
}

The compiler complains about signature missmatch for the t_encode function

  Signature mismatch:
  ...
  In module Dict:
  Values do not match:
    let t_encode: ('a => Js.Json.t, Js.Dict.t<'a>) => Js.Json.t
  is not included in
    let t_encode: ('a => Js.Json.t) => t<'a> => Js.Json.t

How could I handle this case ? I tried the dot notation but without success :thinking:

Thanks again !

Isn’t it just a matter of following the signature and manually curry the function now that there’s no auto-currying?

let t_encode = (encoder) => (dict) => Js.Json.Object(...)

I tried but still get this fun missmatch :grin:

  Signature mismatch:
  ...
  In module Dict:
  Values do not match:
    let t_encode: ('a => Js.Json.t) => t<'a> => Js.Json.t
  is not included in
    let t_encode: ('a => Js.Json.t) => t<'a> => Js.Json.t

well well well that’s a known issue here, long story short, there’s a bug in how the compiler displays the error and I haven’t been able to solve it yet, but meanwhile anyway, to fix the error in itself, you’d better use RescriptCore.Dict instead of Js.

Running rescript build -w with a compilation error exits with an error code, and I need to manually re-run it after every change until I get it to pass. Once passing, it goes back to restarting properly

1 Like

I believe @DZakh fixed this regression in the upcoming release. Can’t find a link to the PR

1 Like

I’ve just created it Fix watch exiting on error by DZakh · Pull Request #6460 · rescript-lang/rescript-compiler · GitHub

4 Likes

rc-5 is released with a fix Release 11.0.0-rc.5 · rescript-lang/rescript-compiler · GitHub

4 Likes

Something has changed about @deriving(jsConverter) ?
This code works well on v10.x