我正在尝试编写一个简单的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])
。
我尝试修改valueOf
和inspect
,但两者均无效。我怀疑${x}
调用了另一种方法,但我在互联网上找不到。我需要修改什么,以便${x}
为嵌套的Id
单子返回正确的字符串?
答案 0 :(得分:2)
您将要覆盖toString
,而不是valueOf
。与字符串连接(或插入模板字符串)会将值强制转换为字符串,并且您的对象继承Object.prototype.toString
并返回[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;