Quick migration guide to uncurried mode for PPX maintainers?

Is there a summary of AST changes and what needs to be done to migrate old PPXs to the v11?

1 Like

There’s no proper write up AFAIK but here are a few resources:

Also check these compiler files for more info about what has changed, and potential utils you can copy to your project to ease the transition:


Thanks, I will look into those!

Also, the workflow that I’m using right now for migration.

So far, the changes I had to make to build examples with the updated ppx can be summarized as follows:

let f = @res.arity(2) (a, b) => a + b // annotate function definitions
let x = @res.uapp f(1, 2)             // annotate function calls

I annotated all the generated function definitions and function calls, and it worked. However, I haven’t fixed the test suit yet and haven’t run any code, so maybe I’ll discover something else.

P.S. In the linked PRs, @res.optional and @res.partial attributes are also mentioned, but I haven’t needed them so far.


Are @res.arity and @res.uapp documented anywhere?

I see that they’re in the Rescript compiler source code. I know the purpose of the @res.arity decorator, to tell the compiler what we expect the arity of the function to be, but I don’t know the actual behavior. If I have a function with 4 params, and I decorate with @res.arity(2), will the first two params be treated as a single function, and the last two params become curryable? In any case, I expect that my fix will be to always have the arity match the number of args in order to make uncurried functions.

The @res.uapp decorator, is that the inverse companion? Is this telling Rescript to package all of the function parameters up as a single tuple on the backend function invocation?

I’ve never authored a PPX from scratch before, but I’m trying to update one to work with Rescript 11, hence the questions. Thanks for your patience.

@alex.fedoseev the examples you wrote above are in Rescript, but that’s not what your PPX actually does under the hood, right? It seems to me like the PPX runs on the OCaml AST level, after Rescript has parsed and transformed the syntax but before the compiler is run, but I’m not sure.

Your tips on your workflow for upgrading your PPX were helpful. Thank you!

1 Like

I am also converting graphql-ppx right now, and I used some of the examples. I applied the attributes to the function declaration and the application where relevant and it seems to pass tests. I still have to test it in our codebase though to make sure it actually works (probably not yet :wink: ). The PR is here, so that might also help your changes.

I think my intuitive answer as to why we need to annotate the arity in the function declaration is that it is to differentiate between let fn = a => b => a +b and let fn = (a, b) => a+b which might otherwise not be different in the parse tree representation. There are no such thing as multi arity functions in the OCaml parse tree, and ReScript achieves this by annotating. I guess the compiler then checks if the arities actually match with the application as an extra check in uncurried mode. If this all matches up, rescript can emit clean function applications and doesn’t have to do any runtime curry polyfill.

Hey @mrmurphy, it’s pretty much the same, but on the AST level. During the update, I searched for all the generated functions by the ppx and annotated each with the dedicated attribute. I manually counted arguments to pass a correct number to the @res.arity. Here is the commit with the changes.