2

我有以下功能

[@bs.obj]
external route:
  (
    ~_method: string,
    ~path: string,
    ~action: list(string) => unit,
    ~options: Js.t({..})=?,
    unit
  ) =>
  _ =
  "";

由于可以部分应用功能,我希望能够做到这一点:

let get = route(~_method="GET");

但它给了我这个错误:

This expression's type contains type variables that can't be generalized:                                                
(~path: string, ~action: list(string) => unit, ~options: {_.. }=?,                                                       
unit) =>
{. "_method": string, "action": list(string) => unit,
  "options": Js.undefined({.. }), "path": string}

我在这里做错了什么?

4

1 回答 1

4

这实际上不是关于可选参数和柯里化,而是关于值限制和非泛化,也就是弱类型变量。TL;博士; 要么get通过添加参数变成语法函数,例如,,let get () = route(~_method="GET") ();要么为你的模块创建一个*.rei接口文件。

更长的故事

.. 变量表示编译器无法将其简化为普通单态类型的多态类型(因为显然没有使用此函数),也不能相信部分应用程序route(~_method="GET")实际上尚未访问options参数并且可能存储在某处在其中,它应该定义类型。

因此,编译器不能将其作为多态变量,也不能给出具体类型,结果,它会产生一个弱类型变量,可以将其视为未来定义的具体类型的参考单元。就像一个未初始化的类型。稍后将由使用该get函数的代码初始化。如果在一天结束时,该类型从未使用过,它可能会逃出模块的范围,这是 OCaml/Reason 类型规则所禁止的。因此,您应该手动给它一个单型(即,将其限制为某种单态类型),或者创建一个隐藏该值(即,不存在)的接口文件,因此不能泄漏模块的范围。.mli/.rei基本上,只需创建一个与您的名称相同的空文件.ml/.re文件将解决此问题。另一种常见的解决方案是get变成一个句法函数,即具有句法显式变量的东西,例如,

let get () = route(~_method="GET") ();

延伸阅读

于 2019-03-22T13:56:38.590 回答