考虑下面的工作代码:
var randN = x => () => Math.floor(x*Math.random());
var rand10 = randN(10)
times(rand10, 10) // => [6, 3, 7, 0, 9, 1, 7, 2, 6, 0]
randN
是一个函数,它接受一个数字并返回一个RNG,当被调用时,它将返回[0,N-1]范围内的随机int。所以它是特定RNG的工厂。
我一直在使用ramda.js和学习函数式编程理论,我的问题是:是否可以使用ramda以无点样式重写randN
?
例如,我可以写:
var badAttempt = pipe(multiply(Math.random()), Math.floor)
这将满足“无点样式”要求,但不能像randN
那样行事:调用badAttempt(10)
只返回1到10之间的单个随机数,而不是< em> function ,在调用时生成1到10之间的随机数。
我无法找到ramda函数的组合,这使我能够以无点样式进行重写。我不知道这是否只是我的失败,或者使用random
的一些特别之处,它会破坏参照透明度,因此可能与点免费样式不兼容。
randN = pipe(always, of, append(Math.random), useWith(pipe(multiply, Math.floor)), partial(__,[1,1]))
答案 0 :(得分:3)
这将有助于在每次调用函数时抽象函数来重新计算其参数。
thunk = fn => R.curryN(fn.length, (...args) => () => fn(...args))
此功能的唯一目的是在给定的fn
函数中产生一些副作用。
我们有thunk
函数后,我们可以像这样定义randN
:
randN = thunk(R.pipe(S.S(R.multiply, Math.random), Math.floor))
R.times(randN(10), 5) // e.g. [1, 6, 9, 4, 5]
注意:S.S
这里是S combinator from Sanctuary,其效果与R.converge(multiply, [Math.random, identity])
完全相同。
但我确实建议使用无点解决方案,如果它实际上提高了函数的可读性。
答案 1 :(得分:2)
我不知道使用特定库学习函数式编程是否是个好主意,因为lib的特性和功能范式将不可避免地混合在一起。然而,在实践中,Ramda非常有用。它弥合了命令式现实与Javascript:D
中的功能性Fantasy Land之间的差距这是一种手动方法:
// a few generic, reusable functions:
const comp = f => g => x => f(g(x)); // mathematical function composition
const comp2 = comp(comp)(comp); // composes binary functions
const flip = f => x => y => f(y)(x); // flips arguments
const mul = y => x => x * y; // first class operator function
// the actual point-free function:
const randN = comp2(Math.floor)(flip(comp(mul)(Math.random)));
let rand10 = randN(10); // RNG
for (let i = 0; i < 10; i++) console.log(rand10());
值得一提的是randN
是不纯的,因为随机数字的定义是不纯的。
答案 2 :(得分:1)
var randN = R.converge(R.partial, [R.wrap(R.pipe(R.converge(R.multiply, [Math.random, R.identity]), Math.floor), R.identity), R.of])
var rand10 = randN(10)
alert(R.times(rand10, 10)) // => [3, 1, 7, 5, 7, 5, 8, 4, 7, 2]
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.19.1/ramda.js"></script>
&#13;