具有固定字符串值的配置的 ReasonML 绑定函数
ReasonML binding function with config having fixed string values
比方说,我在 Javascript 中有这个函数,它可以根据适当的配置生成字符串:
function func(config) {
// ...
}
此外,我们假设 config
变量具有如下结构(所有这些都不能提供给函数调用):
{
"color": string, // can be: "blue", "red", "green"
"number": int, // can be: any number
"other": string, // can be: "x", "y"
}
如何为此创建适当的绑定?我坚持:
[@bs.deriving abstract]
type options = {
[@bs.optional]
color: [@bs.string] [ | `blue | `red | `green ]
[@bs.optional]
number: int,
[@bs.optional]
other: [@bs.string] [ | `x | `y ]
}
[@bs.module]
external func: options => string = "func";
但是尝试这样使用时它不起作用:
let config = MyModule.config(
~color=`blue,
~number=123,
~other=`x
);
let value = MyModule.func(config);
color
和 other
值是整数,不是字符串。
这是因为在现实中,这些值是variants,而不是试图让它完全像JavaScript,我宁愿尝试更多的东西Reason 的惯用语:
type color = Blue | Green | Red;
type coords = X | Y;
type config = {
color,
coords,
number: int
};
let func = (config: config) => "something"
然后在你的函数内部实际上 return 字符串(如果这是你真正需要的)通过模式匹配提供给 config
.
的正确值
查看工作代码here。
希望对您有所帮助!
@bs
属性通常是未经深思熟虑的 hack,您不应该期望它们能与其他属性一起使用,或者实际上与文档解释或显示示例之外的任何东西一起使用。但是,如果在不希望使用的地方使用某个属性,您通常至少会收到有关该属性未被使用的警告,而您的代码确实如此。
@bs.string
特别是仅适用于外部最外层的类型,即其值将直接传递给外部函数的类型。还有一种使用外部函数创建 JavaScript 对象的方法,它也恰好使用较少的魔法并让您对 API 有更多的控制权。据我所知,与 @bs.deriving
相比,唯一的缺点是您不能使用 @bs.as
之类的东西覆盖字段名称。它们必须是有效的 OCaml 标识符。
这是您使用带有 @bs.obj
注释的外部函数实现的示例:
type options;
[@bs.obj] external options : (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit
) => options = "";
要使用它,您可以像 @bs.deriving
:
一样调用它
let config = options(~color=`blue,~number=123, ~other=`x, ());
但即便如此,我也遇到过传递整数值而不是字符串的边缘情况。出于这个原因,我倾向于完全避免多态变体属性,而是使用普通变体和转换函数。这具有更加惯用、更好地融合以及与非 BuckleScript 代码更具互操作性的额外好处。
使用此方法,您的示例可能如下所示:
type color = Blue | Red | Green;
let colorToString = fun
| Blue => "blue"
| Red => "red"
| Green => "green";
type other = X | Y;
let otherToString = fun
| X => "x"
| Y => "y";
[@bs.obj] external options : (
~color:string=?,
~number:int=?,
~other:string=?,
unit
) => options = "";
[@bs.module] external func: options => string = "func";
let func = (~color=?, ~number=?, ~other=?, ()) =>
func(options(
~color = ?Belt.Option.map(color, colorToString),
~number?,
~other = ?Belt.Option.map(other, otherToString),
()));
let config = func(~color=Blue,~number=123, ~other=X, ());
这是命名参数(具有可选字段的对象)的 JavaScript 习语的情况,需要适应 OCaml/ReasonML 习语(具有实际标记参数的函数)。您将分三步完成此操作。第 1 步,如 Glenn 所示,为配置定义一个外部:
type config;
[@bs.obj] external config: (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit,
) => config = "";
第 2 步,使用配置对象的 JavaScript 样式绑定到 JavaScript 函数:
[@bs.val] external func: config => string = "";
第 3 步,将 JavaScript 函数绑定包装在带有标记参数的 OCaml 惯用函数中:
let func(~color=?, ~number=?, ~other=?, ()) = ()
|> config(~color?, ~number?, ~other?)
|> func;
你可以这样使用它:
let result = func(~color=`blue, ());
比方说,我在 Javascript 中有这个函数,它可以根据适当的配置生成字符串:
function func(config) {
// ...
}
此外,我们假设 config
变量具有如下结构(所有这些都不能提供给函数调用):
{
"color": string, // can be: "blue", "red", "green"
"number": int, // can be: any number
"other": string, // can be: "x", "y"
}
如何为此创建适当的绑定?我坚持:
[@bs.deriving abstract]
type options = {
[@bs.optional]
color: [@bs.string] [ | `blue | `red | `green ]
[@bs.optional]
number: int,
[@bs.optional]
other: [@bs.string] [ | `x | `y ]
}
[@bs.module]
external func: options => string = "func";
但是尝试这样使用时它不起作用:
let config = MyModule.config(
~color=`blue,
~number=123,
~other=`x
);
let value = MyModule.func(config);
color
和 other
值是整数,不是字符串。
这是因为在现实中,这些值是variants,而不是试图让它完全像JavaScript,我宁愿尝试更多的东西Reason 的惯用语:
type color = Blue | Green | Red;
type coords = X | Y;
type config = {
color,
coords,
number: int
};
let func = (config: config) => "something"
然后在你的函数内部实际上 return 字符串(如果这是你真正需要的)通过模式匹配提供给 config
.
查看工作代码here。
希望对您有所帮助!
@bs
属性通常是未经深思熟虑的 hack,您不应该期望它们能与其他属性一起使用,或者实际上与文档解释或显示示例之外的任何东西一起使用。但是,如果在不希望使用的地方使用某个属性,您通常至少会收到有关该属性未被使用的警告,而您的代码确实如此。
@bs.string
特别是仅适用于外部最外层的类型,即其值将直接传递给外部函数的类型。还有一种使用外部函数创建 JavaScript 对象的方法,它也恰好使用较少的魔法并让您对 API 有更多的控制权。据我所知,与 @bs.deriving
相比,唯一的缺点是您不能使用 @bs.as
之类的东西覆盖字段名称。它们必须是有效的 OCaml 标识符。
这是您使用带有 @bs.obj
注释的外部函数实现的示例:
type options;
[@bs.obj] external options : (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit
) => options = "";
要使用它,您可以像 @bs.deriving
:
let config = options(~color=`blue,~number=123, ~other=`x, ());
但即便如此,我也遇到过传递整数值而不是字符串的边缘情况。出于这个原因,我倾向于完全避免多态变体属性,而是使用普通变体和转换函数。这具有更加惯用、更好地融合以及与非 BuckleScript 代码更具互操作性的额外好处。
使用此方法,您的示例可能如下所示:
type color = Blue | Red | Green;
let colorToString = fun
| Blue => "blue"
| Red => "red"
| Green => "green";
type other = X | Y;
let otherToString = fun
| X => "x"
| Y => "y";
[@bs.obj] external options : (
~color:string=?,
~number:int=?,
~other:string=?,
unit
) => options = "";
[@bs.module] external func: options => string = "func";
let func = (~color=?, ~number=?, ~other=?, ()) =>
func(options(
~color = ?Belt.Option.map(color, colorToString),
~number?,
~other = ?Belt.Option.map(other, otherToString),
()));
let config = func(~color=Blue,~number=123, ~other=X, ());
这是命名参数(具有可选字段的对象)的 JavaScript 习语的情况,需要适应 OCaml/ReasonML 习语(具有实际标记参数的函数)。您将分三步完成此操作。第 1 步,如 Glenn 所示,为配置定义一个外部:
type config;
[@bs.obj] external config: (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit,
) => config = "";
第 2 步,使用配置对象的 JavaScript 样式绑定到 JavaScript 函数:
[@bs.val] external func: config => string = "";
第 3 步,将 JavaScript 函数绑定包装在带有标记参数的 OCaml 惯用函数中:
let func(~color=?, ~number=?, ~other=?, ()) = ()
|> config(~color?, ~number?, ~other?)
|> func;
你可以这样使用它:
let result = func(~color=`blue, ());