PureScript FFI and JavaScript modules: choosing a multi-argument calling convention
0 reputation · 30 Mar 2020, 16:50 UTC
0 reputation · 30 Mar 2020, 16:50 UTC
When a PureScript module exposes a two-argument function to JavaScript through the FFI, the calling convention must be decided at the language boundary. The default expectation is a curried JavaScript export, but the standard library also provides Data.Function.Uncurried with types such as Fn2 and helpers like mkFn2 and runFn2 to model uncurried functions explicitly.
The uncertainty is that the PureScript compiler does not statically verify JavaScript FFI exports against the declared PureScript type. A curried/uncurried mismatch compiles successfully but produces a runtime TypeError. Because there is no native uncurried syntax and no compiler flag or default lint rule that resolves the tradeoff, each module must choose between accepting curried FFI boilerplate or introducing explicit Uncurried wrappers on both sides. The exact runtime representation of Fn2 and related types is defined by library FFI and may vary across compiler versions, so any convention should be validated against the generated JavaScript for the specific toolchain in use.
For a low-traffic workload where maintainability matters more than raw call overhead, should the default curried representation be preferred over Fn2 wrappers for multi-argument foreign imports? Without static boundary checks, what review or testing approach reliably catches calling-convention mismatches before deployment? Is a per-module convention sufficient, or is there a community-standard default that teams should adopt?
For low-traffic workloads prioritizing maintainability, the default curried representation should be preferred over explicit Fn2 wrappers.
PureScript functions are inherently curried. When exposing a two-argument function to JavaScript via FFI, the standard expectation is that the JavaScript export returns a function waiting for the second argument, not a single function accepting both arguments simultaneously. The Data.Function.Uncurried types explicitly model uncurried behavior, but the compiler does not enforce consistency across the language boundary; a mismatch results in a runtime TypeError.
Since static checks are absent at the boundary, reliable pre-deployment verification requires testing from both sides:
A per-module, documented convention is sufficient; there is no universal community standard overriding the idiomatic curried default.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.