我有两个谓词
interface Foo {}
interface Bar {}
declare const isFoo: (a:unknown):a is Foo
declare const isBar: (a:unknown):a is Bar
组合两个谓词以创建新谓词的功能方法是什么(为了简单起见,假设它是a => isFoo(a) && isBar(a)
?
对于fp-ts
,我最初认为我可以使用fold(monoidAll)([isFoo, isBar])
,但fold
希望数组是布尔型的,而不是计算为布尔型的函数。
这适用于
import { monoid as M, function as F, apply as A, identity as I, reader as R } from 'fp-ts'
interface Foo{}
interface Bar{}
declare const isFoo:(a:unknown) => a is Foo
declare const isBar:(a:unknown) => a is Bar
const isFooAndBar = F.pipe(A.sequenceT(R.reader)(isFoo, isBar), R.map(M.fold(M.monoidAll)))
但是男孩霍迪是那么的复杂。我想还有别的办法。我最终编写了自己的monoid,它接受两个谓词并将它们组合在一起,称之为monoidPredicateAll
:
const monoidPredicateAll:M.Monoid<Predicate<unknown>> = {
empty: ()=>true,
concat: (x,y) => _ => x(_) && y(_)
}
有没有一种规范的FP方式来组合两个谓词?我知道我可以做一些类似的事情
xs.filter(x => isFoo(x) && isBar(x))
但是,如果有更多的谓词,它可能会变得复杂,并且重新使用monoid会使我不太可能在指所有&&
时犯isFoo(x) || isBar(x) && isBaz(x)
这样的拼写错误(这就是xs.filter(fold(monoidPredicateAll)(isFoo,isBar,isBaz))
的帮助所在。
我在SO上找到了关于这一点的讨论,但它是关于Java和内置的Predicate
类型的,所以没有直接回答我的问题。
是的,我想得太多了:(
我最终做了这个:
export const monoidPredicateAll:Monoid<Predicate<unknown>> = {
empty: ()=>true,
concat: (x,y) => _ => x(_) && y(_)
}
然后我可以做
import {monoid as M} from 'fp-ts'
declare const isFoo: Predicate<number>
declare const isBar: Predicate<number>
const isFooAndBar = M.fold(monoidPredicateAll)([isFoo,isBar])
对于其他正在寻找有效解决方案的人,基于@user1713450的答案
import * as P from 'fp-ts/lib/Predicate';
import * as M from 'fp-ts/Monoid';
const createMonoidPredicateAll = <T>(): M.Monoid<P.Predicate<T>> => ({
empty: () => true,
concat: (x, y) => (_) => x(_) && y(_),
});
export const combine = <T>(predicates: P.Predicate<T>[]) =>
M.concatAll(createMonoidPredicateAll<T>())(predicates);