我正在尝试在TypeScript中实现monad;尤其是this example中的join
方法。
要解决的问题如下:
const mm3 = new Maybe(new Maybe(3)); // Maybe<Maybe<number>>
const m3 = mm3.join(); // Maybe<number>
join
方法取消嵌套两个Maybe
的嵌套。但是,在调用Maybe
时可以进入join
的三种状态。预期的输出如下所示。
new Maybe(new Maybe(3)).join(); // Maybe<number>(3)
new Maybe<number>(null).join(); // Maybe<number>(null)
new Maybe(3).join(); // 3 - Not the normal use-case for join()
interface IMonad<T> {
join(): T; // Works for cases #1 and #3 above but
// really I want to express that we're
// returning an IMonad<number> in the examples.
// Or even better, a Maybe<number> in the case of Maybe
}
class Maybe<T> implements IMonad<T> {
private value: T | null;
public constructor(value: T | null | undefined) {
this.value = (value === null || value === undefined) ? null : value;
}
public join(): T {
if (this.value === null) {
return Maybe.of<??>(null); // 'number' in these examples
} else {
return this.value;
}
}
}
我正在努力弄清这可能如何工作。有任何想法吗? TypeScript甚至可以使用,还是我需要higher kinded types?
答案 0 :(得分:2)
只要您不想代表Monad
本身,就很容易实现Maybe
的单个 instances (例如Monad
),需要higher-kinded types ...,而TypeScript对此没有直接支持。 (似乎some people有come up with一些间接支持,但是没有足够干净的地方,我想在这里推荐)
如果您要强烈键入Maybe.prototype.join()
,而不必担心代码中的“ Monad
”,我建议使用通用的this
parameter,如下所示:
class Maybe<T> {
constructor(public value?: T) {}
join<U>(this: Maybe<Maybe<U>>) { // this parameter
return new Maybe(
typeof this.value === "undefined" ? undefined : this.value.value
);
}
}
(我在这里仅将undefined
作为“无”值;如果需要,您可以添加对null
的支持)
this
参数要求在匹配类型的对象上将其作为方法调用。因此,通过将join()
的{{1}}设为某个通用this
的{{1}},我们可以保证Maybe<Maybe<U>>
本身(如果不是U
的话this.value
属性。
让我们测试一下:
undefined
这正是您想要看到的。另请注意,调用value
是编译时错误:
const mm3 = new Maybe(new Maybe(3)); // Maybe<Maybe<number>>
const m3 = mm3.join(); // Maybe<number>
这对我来说似乎是正确的行为;您不能m3.join()
使用非嵌套的monad。
好的,希望能有所帮助;祝好运!