0

我有两个谓词

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)))

但是男孩,你好是令人费解的。我以为可能有另一种方式。我最终编写了自己的幺半群,它接受两个谓词并将它们组合起来,称之为monoidPredicateAll

const monoidPredicateAll:M.Monoid<Predicate<unknown>> = {
  empty: ()=>true,
  concat: (x,y) => _ => x(_) && y(_)
}

是否有一种结合两个谓词的规范 FP 方式?我知道我可以做类似的事情

xs.filter(x => isFoo(x) && isBar(x))

但是它可能会因为更多的谓词而变得复杂,并且重新使用一个幺半群使得我不太可能像isFoo(x) || isBar(x) && isBaz(x)我的意思一样做错字&&(这就是 axs.filter(fold(monoidPredicateAll)(isFoo,isBar,isBaz))会有所帮助的地方。

我在 SO 上找到了关于这个的讨论,但它是关于 Java 和内置Predicate类型的,所以没有直接解决我的问题。

是的,我想太多了:)

4

2 回答 2

1

我最终这样做了:

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])
于 2020-12-17T07:22:47.303 回答
0

对于其他正在寻找工作解决方案的人,基于@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);



于 2021-10-05T20:28:30.473 回答