我一直在尝试学习函数式编程,但我仍然很难像一个函数式编程者一样思考。其中一个难点是如何实现依赖于循环/执行顺序的索引密集型操作。
例如,考虑以下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 等)中,会是什么样子呢?我一直在学习关于单子的知识,认为它们可能与此相关,但我的理解还不够好。
0,a[0],a[a[0]],a[a[a[0]]],...
需要随机访问(除了假设所有元素都是有效索引之外)。在这些罕见的情况下,我们会采用数组,例如Data.Vector
。当需要时,Haskell可以用于命令式编程--只是我们很少需要这样做。 - chiList
实现为链表)?有一些函数式语言拥有不是 ADT 的值类型,例如 Swift 的 Array 或者 Haskell 的 Vector(如上所述),尽管后者不支持 O(1) 更新。 - FeuermurmelprefixList()
只依赖于传入其参数的数据,而且除了返回值之外没有任何影响。这就是“纯函数”的本质。当然,有些编程语言比其他语言更容易编写函数式代码,我会将 Java 的函数式编程能力评为 10 分中的 4.5 分。 - Feuermurmel