简体   繁体   English

使用 FP-TS 合并类型化结构

[英]Merging typed structs with FP-TS

When using FP-TS I often end up with structs being inside a Task or an IO .使用 FP-TS 时,我经常会在TaskIOIO I managed to solve the problem by writing a merge function and separate lift functions that make it work with Task or IO .我设法通过编写合并 function 和单独的提升功能来解决问题,使其与TaskIO See the included code example for a more detailed explanation.有关更详细的说明,请参阅包含的代码示例。 The code works but I'm wondering if the custom functions I wrote are already available in FP-TS in some shape or form.该代码有效,但我想知道我编写的自定义函数是否已经以某种形式或形式在 FP-TS 中可用。

import { deepStrictEqual as assertEqual } from 'assert'
import { IO, of, io, map } from 'fp-ts/lib/IO';
import { sequenceT } from 'fp-ts/lib/Apply';
import { pipe, tupled } from 'fp-ts/lib/function';

type Merge<A, B> = A & B
function merge<A, B>(a: A, b: B): Merge<A, B> {
  return {...a, ...b}
}

type Foo = { foo: 123 }
type Bar = { bar: 456 }
type FooBar = Merge<Foo, Bar>;

const foo: Foo = { foo: 123 }
const bar: Bar = { bar: 456 }
const fooBar: FooBar = merge(foo, bar)

type IOLift<A, AS extends Array<any>, B> = (a: IO<A>, ...as: { [I in keyof AS]: IO<AS[I]> }) => IO<B> 
function ioLift<A, AS extends Array<any>, B>(f: (a: A, ...as: AS) => B): IOLift<A, AS, B> {
  return (...a) => pipe(
    sequenceT(io)(...a),
    map(tupled(f))
  )
}

const ioMerge = ioLift(merge)

const ioFoo: IO<Foo> = of(foo)
const ioBar: IO<Bar> = of(bar)
const ioFooBar: IO<FooBar> = ioMerge(ioFoo, ioBar)

assertEqual(ioFooBar(), fooBar)

Merging structs of the same type can be achieved with a Monoid instance (see getStructMonoid ), but you're looking to merge structs with different interfaces, and there's not a type class for that operation.可以使用Monoid实例来合并相同类型的结构(请参阅getStructMonoid ),但是您希望合并具有不同接口的结构,并且该操作没有 class 类型。 However, Object.assign is equivalent to your merge function, except that it can merge up to four arguments (any more than that and you'll get an any in TypeScript).但是, Object.assign等效于您的merge function,除了它最多可以合并四个 arguments(除此之外,您将在 TypeScript 中得到一个any )。

As for ioLift , there's nothing equivalent to that in fp-ts , but your implementation of sequenceT + map is the standard way of applying a function to some arguments when they each happen to be wrapped in some applicative functor, standard for fp-ts , that is, given the limitations of TypeScript (see @gcanti's comment here about why there's not liftN function). As for ioLift , there's nothing equivalent to that in fp-ts , but your implementation of sequenceT + map is the standard way of applying a function to some arguments when they each happen to be wrapped in some applicative functor, standard for fp-ts ,也就是说,鉴于 TypeScript 的局限性(请参阅@gcanti 的评论了解为什么没有liftN功能)。

Given how trivial the sequenceT + map composition is, one could argue that it doesn't meet the Fairbairn Threshold , meaning it's easier to just combine sequenceT + map inline whenever you find yourself in this situation rather than writing a specialized utility liftWhatever for every applicative functor you come across.考虑到sequenceT + map组合是多么微不足道,有人可能会争辩说它不符合Fairbairn Threshold ,这意味着只要你发现自己处于这种情况,将sequenceT + map内联更容易,而不是为每个应用程序编写一个专门的实用程序liftWhatever你遇到的函子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM