1

使用fp-ts。我有一个数组选项

const arrayofKeys: Option<Array<K>>, 

和一个记录选项

const record: Option<Record<K,V>>

我想选择 Ks 与数组相交的记录的 Vs 并将结果粘贴到选项中。

在拉姆达:R.pick(arrayOfKeys, record)

我如何使用 fp-ts 或 fp-ts 生态系统中的其他软件包解决这个问题?

4

2 回答 2

2

Ramda提升了一些值的函数以处理这些值的容器。只要fp-ts支持FantasyLand Apply规范,就可能会做你想做的事。lift lift (pick)Option

const {of} = folktale.maybe
const {lift, pick} = R

const keys = of (['k', 'e', 'y', 's'])  // Maybe (['k', 'e', 'y', 's'])
const record = of ({s: 1, k: 2, y: 3, b: 4, l: 5, u: 6, e: 7}) // Maybe ({s: 1, k: 2, ...})

console .log (lift (pick) (keys, record) .toString())
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/folktale/2.0.0/folktale.min.js"></script>

于 2022-01-25T22:55:29.403 回答
2

我个人会避免使用 Ramda 等人,因为根据我的经验,它们的类型不是很好。这是一个纯 fp-ts 方法(Str.fromNumber来自 fp-ts-std,被简单替换):

declare const arrayOfKeyNums: Option<Array<number>>
const arrayOfKeys = pipe(arrayOfKeyNums, O.map(A.map(Str.fromNumber)))
declare const record: Option<Record<string, number>>

const keyIntersectedVals: O.Option<Array<number>> = pipe(
  sequenceT(O.Apply)(arrayOfKeys, record),
  O.map(([ks, rec]) =>
    pipe(
      rec,
      R.foldMapWithIndex(Str.Ord)(A.getMonoid<number>())((k, v) =>
        A.elem(Str.Eq)(k)(ks) ? [v] : [],
      ),
    ),
  ),
)

由于需要传递类型类实例,因此有点冗长。从好的方面来说,使用 typeclass 实例意味着可以轻松更新它以支持任何值类型,包括具有任何给定的非原始类型Eq

下面是在 Haskell 中的 body 可能看起来的比较,其中不需要传递 typeclass 实例:

keyIntersectedVals :: Maybe [Int]
keyIntersectedVals = uncurry (M.foldMapWithKey . intersectedToList) <$> sequenceT (mkeys, mmap)
  where intersectedToList ks k v
          | k `elem` ks = [v]
          | otherwise   = []

例如,给定键O.some(["a", "c"])和记录O.some({ a: 123, b: 456, c: 789 }),我们得到O.some([123, 789])

于 2022-02-18T14:42:50.190 回答