如何更改模板字符串外推的值

How to change the value that a template string extrapolates

我正在尝试编写一个简单的 Id monad 来尝试和学习。

这是我写的:

const util = require('util');

const Id = x => ({
  [util.inspect.custom]: () => `Id(${x})`,
  map: f => Id.of(f(x)),
  flatMap: f => f(x),
  valueOf: () => `Id(${x})`,
});

Id.of = Id;

const foo = Id.of('foo');
const toUpper = str => Id.of(str.toUpperCase());

const fooBoxed = foo.map(toUpper); // Oh oh, should be Id(Id('FOO'));
const FOO = foo.flatMap(toUpper); // Yay, Id('FOO');

console.log(fooBoxed);
console.log(FOO);

fooBoxed 应该注销 Id(Id(Foo)),但它会注销 Id([object object])。 我尝试修改 valueOfinspect 但两者都不起作用。我怀疑 ${x} 调用了不同的方法,我在互联网上找不到那个方法。我必须修改什么才能使 ${x} returns 嵌套 Id monad 的正确字符串?

您需要覆盖 toString,而不是 valueOf。与字符串连接(或插入模板字符串)会将值强制转换为字符串,并且您的对象继承 Object.prototype.toString which returns [object …].

const Id = x => ({
  toString: () => `Id(${x})`,
  map: f => Id.of(f(x)),
  flatMap: f => f(x),
});

Id.of = Id;

const foo = Id.of('foo');
const toUpper = str => Id.of(str.toUpperCase());

const fooBoxed = foo.map(toUpper);
const FOO = foo.flatMap(toUpper);

console.log(fooBoxed.toString()); // Yay, Id(Id('FOO'));
console.log(FOO.toString()); // Yay, Id('FOO');

但是,由于您似乎打算将其用于调试,因此您实际上应该使用 x 值的调试表示。为此,请自己致电 util.inspect()

const util = require('util');

const Id = x => ({
  [util.inspect.custom]: () => `Id(${util.inspect(x)})`,
//                                   ^^^^^^^^^^^^
  map: f => Id.of(f(x)),
  flatMap: f => f(x),
  valueOf: () => x,
});
Id.of = Id;