具有多参数和条件的 Ramda
Ramda with multi parameter and conditions
我是函数式编程的新手,任何人都可以帮助我如何将此函数转换为最佳功能
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))
在 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>
在 Ramda 中,您倾向于将要操作的数据作为函数的最后一个参数传递。所有其他参数都可以看作是应用于数据的过程的配置。
知道了这一点,您的函数签名可能应该如下所示:a(defaultValue, func, value)
这允许您构建具有预定义行为的柯里化函数:
const incOr42 = a(42, inc);
incOr42(1); // 2
incOr42(null); // 42
现在让我们把问题分解成更小的部分:
首先,让我们验证一下 func
,它本身可能是一个函数:
如果给 checkFn
的东西不是一个函数,它 return 就是一个函数,它总是 return 它的参数。否则它 return 是原始函数
const checkFn = unless(is(Function), always(identity));
checkFn(add(8))(5); // 13
checkFn('foo')(5); // 5
其次,让我们构建一个接受两个参数的函数:defaultValue
和 func
。
它将 return 接受 value
和 return 的函数 defaultValue
如果 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>
我真的看不出有什么理由超越显而易见的范围。
这个版本似乎完全符合您的要求,而且可读性很强:
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>
你基本上是在发明 Option 类型;有时称为 Maybe。使用像 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.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 上的流行模块,例如 data/maybe.
我是函数式编程的新手,任何人都可以帮助我如何将此函数转换为最佳功能
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))
在 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>
在 Ramda 中,您倾向于将要操作的数据作为函数的最后一个参数传递。所有其他参数都可以看作是应用于数据的过程的配置。
知道了这一点,您的函数签名可能应该如下所示:a(defaultValue, func, value)
这允许您构建具有预定义行为的柯里化函数:
const incOr42 = a(42, inc);
incOr42(1); // 2
incOr42(null); // 42
现在让我们把问题分解成更小的部分:
首先,让我们验证一下 func
,它本身可能是一个函数:
如果给 checkFn
的东西不是一个函数,它 return 就是一个函数,它总是 return 它的参数。否则它 return 是原始函数
const checkFn = unless(is(Function), always(identity));
checkFn(add(8))(5); // 13
checkFn('foo')(5); // 5
其次,让我们构建一个接受两个参数的函数:defaultValue
和 func
。
它将 return 接受 value
和 return 的函数 defaultValue
如果 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>
我真的看不出有什么理由超越显而易见的范围。
这个版本似乎完全符合您的要求,而且可读性很强:
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>
你基本上是在发明 Option 类型;有时称为 Maybe。使用像 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.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 上的流行模块,例如 data/maybe.