【发布时间】:2022-04-05 20:51:12
【问题描述】:
我一直在努力学习函数式编程,但我仍然难以像函数式程序员那样思考。一种这样的挂断是如何实现高度依赖循环/执行顺序的索引繁重的操作。
例如,考虑以下 Java 代码:
public class Main {
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8,9);
System.out.println("Nums:\t"+ nums);
System.out.println("Prefix:\t"+prefixList(nums));
}
private static List<Integer> prefixList(List<Integer> nums){
List<Integer> prefix = new ArrayList<>(nums);
for(int i = 1; i < prefix.size(); ++i)
prefix.set(i, prefix.get(i) + prefix.get(i-1));
return prefix;
}
}
/*
System.out:
Nums: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Prefix: [1, 3, 6, 10, 15, 21, 28, 36, 45]
*/
这里,在prefixList函数中,首先克隆了nums列表,然后对其进行了迭代操作,其中索引i上的值依赖于索引i-1(即需要执行顺序) .然后返回这个值。
这在函数式语言(Haskell、Lisp 等)中会是什么样子?我一直在学习 monad,认为它们在这里可能是相关的,但我的理解仍然不是很好。
【问题讨论】:
-
如下所述,这不是一个真正需要索引的示例。事实上,许多常用算法不需要索引。尽管如此,还是有一些做:例如,计算序列
0, a[0], a[a[0]], a[a[a[0]]], ...需要随机访问(假设所有元素都是有效索引)。在那些罕见的情况下,我们求助于...数组,例如Data.Vector。 Haskell 可以在需要时强制使用——我们只是很少需要这样做。 -
您的实现已经完美运行。
prefixList()不依赖于在其参数中传递的任何其他数据,并且除了其返回值之外没有任何影响。这就是纯函数的本质。或者当然有些语言比其他语言更容易编写函数式代码,我认为 Java 的 10 个 lambdas 中大约有 4.5 个。 -
@Feuermurmel 我的问题与任何算法的关系都比我作为示例提供的前缀更相关。我正在尝试学习如何应用思维模式来摆脱总是使用索引。
-
@AaronC 这当然是一个公平的目标,尝试根据整个列表的转换来实现列表算法,而不是通过索引显式访问单个元素!困扰我的是这个标题,因为它暗示函数式语言本身不能处理基于索引的算法。
标签: haskell functional-programming lisp