我是函数编程的新手,任何可以帮助我将函数转换为最佳功能的人
const isNotNil = R.complement(R.isNil);
const isFunction = R.is(Function)
const a = (value, value2, fn) => {
if (isNotNil(value)) {
return isFunction(fn) ? fn(value) : value
}
return value2;
};
a(5,2, R.add(8))
答案 0 :(得分:1)
在FP中,您应尝试尽可能地分解关注点,并避免使用可选参数,而应使用较小的部分来驱动流程。
此外,Ramda很有用,但缺少一些数据类型,例如Maybe
,在这种情况下可能真的有用。看看SanctuaryJS。
以下代码使用纯函数方法完全可以实现您想要的
const { toMaybe, maybe, pipe } = sanctuary
const a = f => value => value2 => pipe ([
toMaybe, // converts to Just (value) or Nothing, when nil
maybe (value2) (f) // if Nothing, value2, otherwise, value is passed to f
]) (value)
// Output: 3
const output1 = a (x => x + 1) (2) (4)
console.log ('output1: ', output1)
// Output: 4
const output2 = a (x => x + 1) (null) (4)
console.log ('output2: ', output2)
<script src="https://bundle.run/sanctuary@0.15.0"></script>
请注意,我没有检查f
是Function
。 JavaScript是一种动态类型的语言:只需假设它将是Function
,否则它就会快速失败。
const { toMaybe, maybe, pipe } = sanctuary
// Re-arranged parameters: now value is the latest one.
const a = f => value2 => pipe ([
toMaybe, // converts to Just (value) or Nothing, when nil
maybe (value2) (f) // if Nothing, value2, otherwise, value is passed to f
])
// Output: 3
const output1 = a (x => x + 1) (4) (2)
console.log ('output1: ', output1)
// Output: 4
const output2 = a (x => x + 1) (4) (null)
console.log ('output2: ', output2)
<script src="https://bundle.run/sanctuary@0.15.0"></script>
答案 1 :(得分:1)
在Ramda中,您倾向于将要操作的数据作为函数的最后一个参数传递。所有其他参数都可以看作是应用于数据的流程的配置。
知道这一点后,您的函数签名应该看起来像:a(defaultValue, func, value)
这使您可以使用预定义的行为来构建咖喱函数:
const incOr42 = a(42, inc);
incOr42(1); // 2
incOr42(null); // 42
现在让我们看一下将问题分解成小块:
首先,让我们验证func
,它本身可以是一个函数:
如果给checkFn
的东西不是函数,它将返回一个始终返回其参数的函数。否则,它将返回原始功能
const checkFn = unless(is(Function), always(identity));
checkFn(add(8))(5); // 13
checkFn('foo')(5); // 5
其次,让我们构建一个接受两个参数的函数:defaultValue
和func
。
它将返回一个接受value
的函数,如果defaultValue
为nil,则返回value
,否则返回func
const a = useWith(ifElse(isNil), [always, checkFn]);
const incOr42 = a(42, inc);
incOr42(1); // 2
incOr42(null); // 42
将所有内容放在一起:
const {unless, is, always, identity, ifElse, isNil, useWith, inc} = R;
const checkFn = unless(is(Function), always(identity));
const a = useWith(ifElse(isNil), [always, checkFn]);
const incOr42 = a(42, inc);
console.log(incOr42(1));
console.log(incOr42(null));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
答案 2 :(得分:1)
我真的没有太多理由超越显而易见的地方。
此版本似乎完全可以满足您的要求,并且可读性强:
const {is, isNil} = R
const a = (val, val2, fn) => isNil(val) ? val2 : is(Function, fn) ? fn(val) : val
console.log(a(5, 2, R.add(8))) //=> 13
console.log(a(5, 2, 'NonAFunction')) //=> 5
console.log(a(null, 2, R.add(8))) //=> 2
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
答案 3 :(得分:1)
您基本上是在发明 Option 类型;有时称为也许。使用像daggy
这样的简单标记联合库,我们可以实现 Option -
const daggy = require('daggy')
const Option = daggy.taggedSum('Option', {
Some: ['x'],
None: [],
})
const { Some, None } = Option
Option.prototype.map = function(f) {
return this.cata({
Some: x => Some(f(x)),
None: _ => this
})
}
const add = x => y => x + y
console.log
( Some(1).map(add(10)) // Some(11)
, None.map(add(10)) // None
)
我们可以添加一个withDefault
方法,该方法允许我们返回到正常值-
Option.prototype.withDefault = function (x) {
return this.cata({
Some: x => x,
None: _ => x
})
}
console.log
( Some(1).map(add(10)).withDefault(0) // 11
, None.map(add(10)).withDefault(0) // 0
)
最后,一个将普通值转换为我们新的Option类型的构造函数-
Option.fromNullable = function (x) {
if (x == null)
return None
else
return Some(x)
}
console.log
( Option.fromNullable(1).map(add(10)).withDefault(0) // 11
, Option.fromNullable(null).map(add(10)).withDefault(0) // 0
)
如果您仍然需要将此表达式表示为函数,例如问题中的a
-
const a = R.curry((f, x, y) =>
Option.fromNullable(x).map(f).withDefault(y))
console.log
( a (R.add(8), 5, 2) // 13
, a (R.add(8), null, 2) // 2
)
Ramda不包含内置的 Option 或 Maybe ,但是如果您正在寻找现有的实现,npm上有一些流行的模块,例如{{3 }}。