Loops 函数式中的For循环
在函数式编程书籍中,一个反复出现的主题是FP意味着告诉计算机做什么,而不是如何做。给出了一些代码示例,如:Loops 函数式中的For循环,loops,for-loop,functional-programming,Loops,For Loop,Functional Programming,在函数式编程书籍中,一个反复出现的主题是FP意味着告诉计算机做什么,而不是如何做。给出了一些代码示例,如: val newNumbers = oldNumbers.map(_ * 2) 解释是,我们不使用传统的for循环,而是使用映射 但是不是map内部实现for循环。所以我们刚刚将for循环从代码转移到了其他部分。 那么,它究竟是如何使FP优于命令式的呢?去容忍和命令式 让我们继续使用您的示例,并将所有值加倍 命令 计算机,从第一个索引到最后一个索引,每次索引小于数组长度时,都增加当前索引
val newNumbers = oldNumbers.map(_ * 2)
解释是,我们不使用传统的for循环
,而是使用映射
但是不是map
内部实现for循环。所以我们刚刚将for循环从代码转移到了其他部分。
那么,它究竟是如何使FP优于命令式的呢?去容忍和命令式
让我们继续使用您的示例,并将所有值加倍
- 计算机,从第一个索引到最后一个索引,每次索引小于数组长度时,都增加当前索引。如果当前索引较小,请将当前索引加倍并将其添加到新数组中,否则将返回新数组。
function double(arr) {
newArray = []
for(index = 0; index < arr.length; i++) {
newArr.push(arr[index] * 2)
}
return newArray
}
双功能(arr){
newArray=[]
对于(索引=0;索引
- 计算机,请给我一个新的数组,所有的值都要加倍 arr.map(double) arr.map(双精度)
const map=fn=>xs=>{
让newArray=[]
for(设i=0;i
x*2
console.log(
地图(双)([1,2,3,4])
)
但是映射函数不是在内部实现for循环吗
通常不会(至少在函数式语言中)。在一些不太多范式的函数式语言中,for循环甚至不存在
map
的一个常见实现是:
map(f, []) = []
map(f, x::xs) = f(x) :: map(f, xs)
那么,它究竟是如何使FP优于命令式风格的呢
因为,即使使用for循环实现了map
,使用map
的代码也可以在没有任何可变变量或数据结构的情况下编写
因此,不必将列表放入可变变量并从循环中重新分配它,或者更糟糕的是,使用可变列表从for循环中插入元素,您可以使用一个包含不可变列表的不可变变量,无论幕后发生了什么,它都可以正常工作。这对于注释来说太长了,也许这确实是一个答案 我将借用Apocalisp的评论: for循环在内部由跳转指令(goto)实现。但你不会因为循环是如何实现的,就放弃循环,到处使用gotos 出于以下原因,我们不再使用GOTO(或longjmp/setjmp):
表示
,表示
,等等(是的,映射
)。我们的意思更清楚,更难(尽管我仍然认为太容易)在这些构造上犯错误
它如何证明FP得分高于命令式?我可以很好地将命令式实现放在一个编码良好的方法中,并在任何需要的地方调用它 是的,你可以这样做。您不应该这样做,因为您应该使用经过良好测试和流行的第三方库或内置语言结构,而不是自己滚动所有内容。即使您是一名出色的开发人员,您也无法与流行编译器的作者(他们往往是该领域的顶尖人物)或数百名在流行的开源库中修复边缘案例bug的贡献者竞争
我可以强制实现一个方法,该方法返回一个新列表而不修改输入列表,并在需要时调用该方法 对。同样,你可以做到。但请考虑以下内容:
function doubleEvery(arr) {
let i;
let l = arr.length;
let result = [];
for (i=0; i<length; ++i) {
result.push(arr[i] * 2);
}
return result;
}
函数双精度(arr){
让我;
设l=arr.length;
让结果=[];
for(i=0;iIt隐藏并抽象实现,而不是总是重新实现itAfor
循环由跳转
指令(goto)在内部实现。但您不会因为循环是如何实现的,就放弃循环,到处使用gotos。@Apocalisp这应该是公认的注释:D@Apocalisp,您能详细说明一下您的答案吗?有时是一个循环。有时是将不同的部分分配给不同的CPU,甚至是不同的群集节点。部分价值在于此时,不再需要预先做出决定;可以透明地针对节点/集群成员等进行分发。将for
循环与map
进行比较有点不公平,因为后者表达性较差。您不能在所有情况下都隐藏递归。我不理解您的不公平是什么意思。另外y我的目标不是隐藏递归,而是为用户创建相同的函数调用-但感谢您的提示!map
只涵盖了可以用for
循环表示的迭代算法的子集。您必须使用其他迭代高阶函数,甚至诉诸显式递归来覆盖它们。all迭代高阶函数用于替换显式递归——这就是我对隐藏递归的意思。它如何证明FP比命令式更优秀?我可以很好地将命令式实现放在一个编码良好的方法中,并在我需要的任何地方调用它。@Mandroid选择一个范例并不是关于哪个“更好”。这是关于您喜欢的推理方式。如果您喜欢数学,请使用FP。如果您喜欢经典软件工程,请使用OOP。如果您对这两个领域都感到满意,请同时使用。我可以强制实现一个方法,该方法返回一个新列表,而无需修改输入列表,然后调用
function doubleEvery(arr) { // iterating is coupled to doubling
let i; // unitialized variable
let l = arr.length;
// Have to allocate result object, no opportunity for compiler
// to optimize it away or use structural sharing
let result = [];
for (i=0; i<length; ++i) { // possible off-by-one error
// Here if it's a more complex operation than simply doubling
// we can't just pull this part out to test it independently
result.push(arr[i] * 2);
}
return result;
}