BuckleScript

BuckleScript

  • Docs
  • Try
  • API
  • Community
  • Blog
  • Languages iconEnglish
    • 日本語
    • Español
    • Français
    • 한국어
    • Português (Brasil)
    • Русский
    • 中文
    • 繁體中文
    • Help Translate
  • GitHub

›Recent Posts

Recent Posts

  • A story of exception encoding in BuckleScript
  • What's new in release 7.3
  • Generalized uncurry support in BuckleScript 7.3
  • Announcing bs-platform 7.2
  • Loading stdlib from memory

Generalized uncurry support in BuckleScript 7.3

March 26, 2020

ReasonML is a curried language, while Js is an uncurried language. When compiling ReasonML into Js, there's lots of headache due to the semantics mismatch.

After several years of research and development, we reach an ideal situation in the next release: adding a lightweight uncurried calling convention to ReasonML.

Why we need native uncurried calling convention

  • The curried call is inherently slower than the uncurried call.

    A native implementation of curried call like purescript does will generate very slow code:

    let curriedFunction = x => y => z => x + y +z ;
    let curriedApply = curriedFunction(1)(2)(3); // memory allocation triggered
    

    BuckleScript does tons of optimizations and very aggressive arity inference so that the curried function is compiled into a multiple-arity function, and when the application is supplied with the exact arguments -- which is true in most cases, it is applied like normal functions.

    However, such optimization does not apply to high order functions:

    let highOrder = (f,a,b)=> f (a, b) 
    // can not infer the arity of `f` since we know
    // nothing about the arity of `f`, unless
    // we do the whole program optimization
    

    In cases where arity inference does not help, the arity guessing has to be delayed into the runtime.

  • Bindings to JS world

    When we create bindings for high order functions in the JS world, we would like to have native uncurried functions which behave the same as JS world -- no semantics mismatch.

Generalized uncurried calling convention in this release

Before release 7.3, we had introduced uncurried calling convention, however, it has serious limitations -- uncurried functions can not be polymorphic, it does not support labels, the error message leaks the underlying encoding -- now all those limitations are gone!

Previously

The error messages above are cryptic and hard to understand. And the limitation of not supporting recursive functions make uncurried support pretty weak.

Now those limitations are all gone, you can have polymorphic uncurried recursive functions and it support labels.

The error message is also enhanced significantly

  • When the uncurried function is used in curried

    let add = (. x, y ) => x + y;
    
    let u = add (1, 2)
    

    The old error message:

    Error: This expression has type (. int, int) => int
        This is not a function; it cannot be applied.
    

    The new error message

    Error: This function has uncurried type, it needs to be applied in ucurried style
    
  • When the curried function is used in the uncurried context

    
    let add = ( x, y ) => x + y;
    
    let u = add (.1, 2)
    

    The old error message:

    Error: This expression has type (int, int) => int
        but an expression was expected of type (. 'a, 'b) => 'c
    

    The new error message:

    Error: This function is a curried function where an uncurried function is expected
    
  • When arity mismatch

    let add = (. x, y ) => x + y;
    
    let u = add (.1, 2,3)
    

    The old message:

    Error: This expression has type (. int, int) => int
        but an expression was expected of type (. 'a, 'b, 'c) => 'd
        These two variant types have no intersection
    

    The new message:

    Error: This function has arity2 but was expected arity3
    

Note the generalized uncurry support also applies to objects, so that you can use obj##meth (~label1=a,~label2=b).

The only thing where the uncurried call is not supported is optional arguments, if users are mostly targeting JS runtime, we suggest you can try uncurry by default and would like to hear your feedback!

You can already test it today by npm install bs-platform@7.3.0-dev.1 (Windows support will be coming soon).

Recent Posts
  • Why we need native uncurried calling convention
  • Generalized uncurried calling convention in this release