了解ReasonML中的Js.Promise.resolve(。)点语法

Hom*_*man 2 promise reason bucklescript

我正在尝试了解文档:https : //reasonml.github.io/docs/en/promise

在用法部分,有:

let myPromise = Js.Promise.make((~resolve, ~reject) => resolve(. 2));
Run Code Online (Sandbox Code Playgroud)

为什么2之前有点?它是什么意思,它是做什么的?

gle*_*nsl 5

(. ) 如此处所用,在函数应用程序中,是指应使用未咖喱的调用约定来调用函数。

当在函数类型(如此处的类型)中使用resolve(. 'a) => unit,表示该函数是未固化的。

好吧,那到底是什么意思?Wweeellll,这只是一个故事。开始:

什么没意思?

不可伪造与可伪造相反,因此让我们先解释一下然后再进行比较。

Currying是将包含多个参数的函数转换为一系列分别具有一个参数并返回最终返回值或具有下一个参数的函数的过程。在Reason / OCaml中,这是为我们自动完成的,这就是为什么在OCaml函数类型的参数之间有箭头(例如'a -> 'b -> 'ret)。您也可以在Reason('a => 'b => 'ret)中以这种方式编写函数类型,但是默认情况下,它被语法(('a, 'b) => 'ret)隐藏,这虽然很好,但也可能使您更难理解为什么函数在某些情况下会表现异常。

在支持一流功能的非咖喱语言中,您也可以手动咖喱函数。让我们看一下ES6中的一个例子。这是正常的“未经处理的” ES6功能:

let add = (a, b) => a + b;
Run Code Online (Sandbox Code Playgroud)

这是它的咖喱形式:

let add = a => b => a + b;
Run Code Online (Sandbox Code Playgroud)

并用括号强调单独的功能:

let add = a => (b => a + b);
Run Code Online (Sandbox Code Playgroud)

第一个函数接受参数a,然后返回一个函数(关闭a),该函数接受参数b,然后计算最终的返回值。

这很酷,因为我们可以轻松地部分使用a参数而无需使用bind,但是一次将所有参数应用到它有点不方便,因为我们必须分别调用每个函数:

let result = add(2)(3);
Run Code Online (Sandbox Code Playgroud)

因此,Reason / OCaml不仅在创建时自动咖喱函数,而且还提供了调用约定,使我们也可以方便地应用多个参数。

这一切都很棒!...只要所有功能都得到保证 但是,然后我们想出去玩,并与JavaScript对话,而大多数功能都不是JavaScript(但请参见Ramda作为一个值得注意的例外)。为了能够调用未编写的JavaScript函数,我们需要一个未编写的调用约定,并且要创建可以从JavaScript中正常调用的函数,我们需要一个未编写的函数类型

为什么resolve需要不加处理?

甚至更好的问题可能是“为什么不是所有外部函数都未经处理”?答案是它们实际上是,但是类型和调用约定通常可以在编译时进行推断。如果不是这样,通常可以在运行时通过检查函数值来“反映”它,而这会以很小的(但很快会增加)性能成本。例外情况是它有点混乱,因为文档没有确切说明何时需要显式的连续显示才能正常运行,什么时候不需要,但出于性能原因可能会有所帮助。此外,实际上有两个针对非咖喱函式的注解,一个可以推论调用约定,另一个要求它必须是显式的,在这里就是这种情况。但这就是我收集的。

让我们看一下的完整签名Js.Promise.make,这很有趣,因为它包含三种非咖喱函数:

[@bs.new]
external make :
    ([@bs.uncurry] (
        (~resolve: (. 'a) => unit,
         ~reject: (. exn) => unit) => unit)) => t('a) = "Promise";
Run Code Online (Sandbox Code Playgroud)

或者使用OCaml语法,在这种情况下,我发现它的可读性更高:

external make : (resolve:('a -> unit [@bs]) ->
                 reject:(exn -> unit [@bs]) -> unit [@bs.uncurry]) -> 'a t = "Promise" [@@bs.new]
Run Code Online (Sandbox Code Playgroud)

第一种功能是make它本身,它是一个外部函数,可以推断为无需处理,因为所有外部函数当然都是用JavaScript实现的。

第二种函数是我们将创建并传递给的回调make。这必须是非咖喱的,因为它是使用非咖喱的调用约定从JavaScript调用的。但是,由于默认情况下我们创建的函数是咖喱的,[@bs.uncurry]因此在此处使用它来指定它期望使用未咖喱的函数,并且应该自动将其取消咖喱。

第三种函数是resolvereject,它们是从JavaScript传回的回调函数,因此是非咖喱函数。但是,这些也是一元函数,您会认为curried和uncurried形式应该完全相同。使用普通的单态函数是正确的,但不幸的resolve是,它是多态的,这会带来一些问题。

如果返回类型是多态的,则该函数实际上可能不是咖喱形式的1-ary,因为返回值本身可以是带有另一个参数的函数,可以返回另一个函数,依此类推。那是欺骗的缺点。但是幸运的是不是,所以我们知道它是1元。

我认为这个问题比这更棘手。之所以会出现这种情况,是因为我们需要能够使用全部为1进制的咖喱函数类型来表示0进制的非咖喱函数。我们该怎么做?好吧,如果您要在Reason / OCaml中实现等效功能,则可以将其unit用作参数类型,让我们开始吧。但是现在,如果您具有多态函数,则将其单态化为unit1 则可能为0 元,否则为1进制。而且我想用一个参数调用0元函数在某种程度上被认为是不合理的。

但是,为什么reject当它不是多态的时,就需要不加处理吗?

好吧...我最好的猜测是它只是为了保持一致性。


有关更多信息,请参见手册(但请注意,这与部分应用程序混淆)