functional-programming - 有没有更好的方法来以无点的方式组合它?
问题描述
我一直在工作中遇到这个用例,我觉得必须有一种方法可以在不将 cat 定义为参数的情况下以无点的方式组合 fullName:
const cats = [
{ name: 'Bob', lastName: 'Ross' },
{ name: 'Frank', lastName: 'Langella' },
];
// this bugs me
const fullName = cat => add(
prop('name', cat),
prop('lastName', cat)
);
const isEqual = curry((a, b) => a === b);
const isBobRoss = compose(isEqual('BobRoss'), fullName);
编辑:上面的一些助手,以防它有助于理解挑战
/**
* compose :: ((a -> b), (b -> c), ..., (y -> z)) -> a -> z
*/
const compose = (...fns) => (...args) =>
fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
/**
* curry :: ((a, b, ...) -> c) -> a -> b -> ... -> c
*/
function curry(fn) {
const arity = fn.length;
return function $curry(...args) {
if (args.length < arity) {
return $curry.bind(null, ...args);
}
return fn.call(null, ...args);
};
/**
* add :: a -> b -> a + b
*/
const add = curry((x, y) => x + y)
/**
* prop :: String -> Object -> a
*/
const prop = curry((p, obj) => obj[p])
}
解决方案
(最初我拒绝为 JS/TS 提供一个特定的函数式编程库,并在一般概念上工作)
请注意,您的 curredprop
函数需要一个键并返回一个 reader monad。这将很有用。
假设type Obj = {name:string,lastName:string}
,那么你的咖喱道具 fn 是(key:'name'|'lastName') => Reader<Obj,string>
您可以使用sequence
type 函数将两个 reader monad 组合成一个,如下所示:
const getNameParts = sequence(prop('name'), prop('lastName')) // Reader<Obj, [string,string]>
然后您可以将 [string,string] 映射为单个字符串,就像在 add 函数中一样
const add = as => as.reduce((acc, item) => acc + item)
因此,如果您可以提升add
阅读器 monad 的计算上下文(这里使用建议的 `map: ((a:A)=>B)=>(fa:F<A>)=>F<B>),然后编写这些操作:
const buildNameFromObject = compose(getNameParts, map(add)) // Reader<Obj, string>
我们有它。
const personsName = buildNameFromObject(someObject) // string
fp-ts
是一个提供我刚才提到的所有内容的库,并使用该库(更改了一些函数名称以与 fp-ts 的词汇表保持一致),
import { reader, map } from 'fp-ts/lib/Reader'
import { sequenceT } from 'fp-ts/lib/Apply'
import { pipe } from 'fp-ts/lib/pipeable'
const getNameParts = sequenceT(reader)(prop('name'), prop('lastName'))
const buildNameFromObject = pipe(getNameParts, map(add)) // Reader<Obj, string>, which is a fancy way of writing (o:Obj)=>string
buildNameFromObject({name:'Foo', lastName: 'Bar'}) // 'FooBar'
您的“fullName”函数 ( buildNameFromObject
) 现在是免费的。
推荐阅读
- multithreading - 线程中的 RwLock::spawn 不会释放锁
- javascript - Vue在列表调用函数中制作最后一项
- ansible - Ansible - 将这两个值添加到 grub.conf
- excel - 如何设置直方图x轴的最大和最小比例?
- python - 如何在主数据集中找到 X_train 索引?
- oracle-adf - 如何使用 autoSuggestBehavior 使用鼠标进行复制和粘贴
- python - AWS Lambda 本地执行时间大于 10 秒但小于 1 秒
- java - Kafka Stream 2.3 反序列化异常处理程序
- netsuite - NetSuite 使用 SuiteScript 中记录上的任何字段查找记录 ID
- maven - Maven 插件即使未在其中声明也会运行
部分