typescript - 使用镜头和遍历获取部分对象并返回 "filled in"对象的函数式编程/光学概念?

标签 typescript functional-programming lenses monocle-scala

(编辑 我正在使用 monocle-ts ,但如果用 monocle-ts 不可能(因为作者甚至说它只是原始 Monocle for Scala 的部分端口)但如果有是任何语言的另一个光学包中的东西,我愿意将这些想法移植到 TypeScript。)

假设我有一个助手类型 Partial<A>这样它就代表了一条记录,该记录有部分或全部,但没有非成员,类型为 A . (所以如果 A = { foo: number, bar: string } 那么 Partial<A> = { foo?: number, bar?: string } )(编辑 这是 Typescript 的内置部分实用程序类型。)

我开始

interface Parent {
  xs: Child[]
}

interface PartialParent {
  partialxs: Partial<Child>[]
}

declare function fillInTheGaps(x: Partial<Child>):Child

假设我组成了一个镜头和遍历组合 ( composedTraversal ) 以便它聚焦在 partialxs 上来自 PartialState然后将其作为数组遍历。这将是 Traversal<PartialState, Partial<Child>> .

假设我有一个 declare const fn = (x:Partial<Child>):Partial<Child>那我可以申请fn所有 child composedTraversal.modify(fn)(partialState)这将产生一个新的 PartialStatefn适用于所有 partialxs .

是否有一些概念可以让我“扩展”或“转换”这种遍历为不同的东西,以便我可以组合镜头和遍历并使用 fillInTheGaps这样我就可以传入 PartialState并取回 State

忽略我的语法是 TypeScript,我添加了 monocle-scala 标签,因为如果这个概念存在,我想它在 Monocle 库中,我可以将这些知识转化为我正在使用的库。

编辑 引发这个问题的问题是我在 Redux 应用程序中有一个表单输入,用户在其中输入数据但大多数都不是必需的。输入在编译时是未知的(它们是从 RESTful API 查询重试的)所以我不能将模型表示为

interface Model {
  foo?: string[]
  bar?: string[]
}

相反,它表示为

interface Model {
  [index:string]: string[]
}

我还可以从 RESTful 服务器获取默认模型。所以我将它们建模为 Parent (来自服务器的内容)和 Partial<Parent> (什么代表用户在应用中的输入)。

在进行一些计算之前,我需要折叠缺失 Prop 的默认值。这是我的fillInTheGaps上面引用的函数。

我的愿望是通过我的代码中的类型来强制执行它的功能,并且因为我已经编写了很多光学器件,所以可以重用其中的一些。我实际上编写了一个镜头和遍历来对这些数据执行其他操作。 myLens.compose(myTraversal).modify(fn)需要 Partial<State>并返回 Partial<State>但我希望将它们组合成一个接受部分并返回整体的函数。

我显然可以只写 const filler: (Partial<State>):State = myLens.compose(myTraversal).modify(fillInTheGaps)然后抛出 //@ts-ignore高于它并知道它会起作用,但这似乎,呃,脆弱。

最佳答案

我想,您可能想要的是 Polymorphic Traversal or PTraversal<S, T, A, B> .

A Traversal<S, A>说,“如果我有一个函数 A => A,我可以使用 modify 来获得一个函数 S => S,它使用原始函数来修改所有的 A出现在 S 中的 s ".

相比之下,PTraversal<S, T, A, B>说,“如果我有一个函数 A => B,我可以使用 modify 来获得一个函数 S => T”,这会转换所有的 ASB , 产生一个 T .

助记的,PTraversal的类型参数是:

  • S PTraversal的来源
  • T PTraversal 的“修改”来源
  • A PTraversal 的目标
  • B PTraversal 的“修改后”目标

PTraversal s 很有用,因为它们可以让您编写如下内容:

PTraversal<Array<A>, Array<B>, A, B>

让你遍历 Array同时更改元素的类型。


在您的特定情况下,您提到了具有两个功能:

declare function fillInTheGaps(x: Partial<Child>):Child
declare function fn(x: Partial<Child>):Partial<Child>

这些可以组合在一起产生一个函数:

function transformAndFill(x: Partial<Child>): Child {
   return fillInTheGaps(fn(x)); 
}

然后你需要写一个PTraversal<PartialState, State, Partial<Child>, Child> .

这将支持与 Lens 组合制作新的 PTraversalTraversal 的方式大致相同做了。

应该是可行的,我认为从你的问题来看,如果你可以转换每个 Partial<Child>PartialStateChild你应该能够制作一个State .


PTraversal存在于 Monocle(Scala 库)中,但不幸的是它看起来不像是 monocle-ts : 因此,不幸的是,您必须编写大量光学库代码才能支持这一点。

关于typescript - 使用镜头和遍历获取部分对象并返回 "filled in"对象的函数式编程/光学概念?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63749061/

相关文章:

haskell - 使用 lens 向嵌套 Map 添加键和值

haskell - 函数参数似乎在类型分析中消失了

javascript - 如何将 promise 连接到这条链?

angular - 名称属性结果为未定义的条件输入

Angular 2 : dynamically making parts of a text clickable

recursion - 鸭图到底有什么作用?

swift - 合并两个字典的通用函数

haskell - 用镜头构造谓词

javascript - lambda js : lens for deeply nested objects with nested arrays of objects

javascript - Nest.js : initialization of property from controller's superclass