提供由 3rd 方脚本绑定的功能

Providing a function that is bound by 3rd party scipt

我正在尝试在 Fsharp 中编写一个 riot 标签,但如果不更改 riot 就无法这样做。

在JavaScript我应该provide a function like:

function(opts) {
  this.on("update",function(opts){
    this.opts = opts || this.opts;
  });
}

riot 将 call this function using Function.prototype.call:

if (impl.fn) { impl.fn.call(this, opts); }

在 F# 中,我尝试了以下操作:

[<Emit("this")>]
let isThis (x: 'a) : obj = jsNative

let bind fn =
  fun o ->
    fn (isThis 1) o 

[<Emit("[=12=] === undefined")>]
let isUndefined (x: 'a) : bool = jsNative

bind
  (
    fun me opts ->
      me?on(
        "update"
        ,(
          fun opts ->
            if not (isUndefined opts) then
              me?opts <- opts
              ()
        )
      )
  )

但是;绑定函数被转换为:

export function bind(fn, o) {
  return fn(this)(o);
}

当我想咖喱时却没有咖喱,我正在寻找的输出是:

export function bind(fn) {
  return function(o){
    return fn(this)(o);
  }
}

我能让它工作的唯一方法是将 riot.js 更改为:

if (impl.fn) { impl.fn(this)(opts); }

并按以下方式在 F# 中提供我的函数:

fun me opts ->
  me?on(
    "update"
    ,(
      fun opts ->
        if not (isUndefined opts) then
          me?opts <- opts
          ()
    )
  )

更改第 3 方库以满足转译器生成的代码并不理想。有没有办法让转译器生成我正在寻找的输出?

[更新]

不需要更改第 3 方代码的更好方法是提供绑定功能作为第 3 方 JavaScript:

然后将其导入并在您的模板代码文件中使用绑定:

let JSI = 
  bind<(obj -> obj -> unit) -> obj>
    "../../../js/3rd/JSI.js"
bind
  (
    fun me opts ->
      me?on(
        "update"
        ,(
          fun opts ->
            if not (isUndefined opts) then
              me?opts <- opts
              ()
        )
      )
  )

您正在与 Fable 的 automatic uncurrying 对抗。您需要做的是用 System.Func 委托替换 F# 函数,以防止 Fable 取消柯里化。

我能够非常接近这个:

[<Emit("this")>]
let jsThis : obj = jsNative

let bind (fn : Func<obj, (obj -> obj)>) = 
  Func<_, _> (fun o -> fn.Invoke(jsThis) o)

生成的JavaScript:

export function bind(fn) {
    return (o) => fn(this)(o);
}