【发布时间】:2019-08-17 03:15:59
【问题描述】:
我最近一直在尝试使用 TypeScript,并且正在尝试实现一些基本的 monad。我已经有了一个功能合理的 Maybe(至少使用与我的以下 Either 相同的方法),但是由于与类型相关的原因我不太明白,但 Either 正在躲避我。
我对高级类型的打字策略是从这篇文章中借用的:https://medium.com/@gcanti/higher-kinded-types-in-typescript-static-and-fantasy-land-d41c361d0dbe。我知道有些库已经拥有所有这些 monad 和其他 FP 好东西,但是像这样实现它们是我尝试更深入地学习 TypeScript 的方式。
declare module './HKT' {
interface TypeIDtoHKT2<E, A> {
Either: Either<E, A>;
}
}
export const TypeID = 'Either';
export type TypeID = typeof TypeID;
export class Left<E> {
readonly _F!: TypeID;
readonly _A!: E;
readonly _tag: 'Left' = 'Left';
constructor(readonly left: E) {}
static of<E, A>(e: E): Either<E, A> {
return new Left(e);
}
map<A, B>(f: (a: A) => B): Either<E, B> {
return this;
}
chain<A, B>(f: (a: A) => Either<A, B>): Either<E, B> {
return this;
}
ap<A, B>(f: Either<A, (a: A) => B>): Either<E, B> {
return this;
}
}
export class Right<A> {
readonly _F!: TypeID;
readonly _A!: A;
readonly _tag: 'Right' = 'Right';
constructor(readonly right: A) {}
static of<A, E>(a: A): Either<E, A> {
return new Right(a);
}
map<E, B>(f: (a: A) => B): Either<E, B> {
return Right.of(f(this.right));
}
chain<E, B>(f: (a: A) => Either<E, B>): Either<E, B> {
return f(this.right);
}
ap<E, B>(f: Either<E, (a: A) => B>): Either<E, B> {
if (f instanceof Left) return f;
return this.map(f.right);
}
}
export type Either<E, A> = Left<E> | Right<A>;
export const left = <E, A>(e: E): Either<E, A> => {
return new Left(e);
};
export const right = <E, A>(a: A): Either<E, A> => {
return new Right(a);
};
当我尝试运行测试断言时,例如right(4).map(isEven) === true,我收到以下错误:
Cannot invoke an expression whose type lacks a call signature. Type '(<E, B>(f: (a: number) => B) => Either<E, B>) | (<A, B>(f: (a: A) => B) => Either<unknown, B>)' has no compatible call signatures.
我不明白为什么 E 类型在这里是 unknown 或者我如何才能让它知道......或者这是否是正确的尝试。任何指导表示赞赏。
【问题讨论】:
-
我在这里尝试了你所有的例子repl.it/repls/ExtralargeFixedAssembly 并且工作得很好。你用的是什么版本的 Node 和 TS?
-
@DamiánRafaelLattenero 我正在使用节点 12.6.0 和 TS 3.5.3。但更重要的是,如果我添加
right(4).map(isEven)它不会编译。见repl.it/repls/BaggySuperficialGlueware -
当我以一种不适合它的方式使用 Javascript 语法时,它被称为 hack。使用 TS 接口来伪造更高种类的类型就是这种滥用,我猜你正在经历的是依赖 hack 的后果。
-
@bob 这是一个公平的观点。我同意这是一个笨拙的解决方案。您是否建议 TS 在这里不是一个好的语言选择,我应该回到在 JS 中使用代数结构?或者您对此类结构有更好的 TS 实现建议?
-
如果你真的想应用类型化的纯功能习语,那么你应该使用 purescript,因为它是经过行业验证的。但是,这是一个艰难的步骤,尤其是当您来自命令式 Javascript 时。如果你坚持 OOP 风格,Typescript 可能是一个不错的选择。
标签: typescript functional-programming either