为什么函数式语言如此大量使用列表?

时间:2016-01-31 14:45:56

标签: list functional-programming

我的意思是列表对其他数据结构有什么优势,使其在函数式语言中几乎不可避免?

2 个答案:

答案 0 :(得分:12)

“没有勺子。”

如果我告诉你没有字符串那么怎么办?只存在单个字符列表。

那么如果我告诉你没有列表这样的东西怎么办?只有对。

; construct a pair of a and b
(cons 'a 'b)           ; => ('a 'b)

; get the first element of the pair
(first (cons 'a 'b))   ; => 'a

; get the second element of the pair
(second (cons 'a 'b))  ; => 'b

; create a "list"
(define x (cons 'a (cons 'b (cons 'c (cons 'd (cons 'e null))))))
; => ('a ('b ('c ('d ('e ())))))

; get the third element in the "list", x
(first (second (second x)))
; => 'c

如果我告诉你没有配对的话怎么办?只有lambdas。

(define (cons x y)
  (λ (f) (f x y)))

(define (first p)
  (p (λ (x y) x)))

(define (second p)
  (p (λ (x y) y)))

当然这只是一种可能的实现方式。但重要的是要意识到这只是一种幻觉。

数据抽象真的很神奇。良好的语言允许您发明任何您希望使用的结构,并定义任何构造函数/选择器,使其适用于您的结构。有些语言比其他语言提供更多的语法糖。

列表很常见,因为作为程序员,我们经常处理有序的事物集合。其他常见类型是集合和地图。只是不要欺骗自己认为它是超级特殊的^,^

答案 1 :(得分:4)

功能语言更喜欢不变性,因此,在数据结构方面,函数式语言更喜欢persistent data structures。简而言之,持久性数据结构是数据结构,我们可以继续访问任何以前版本的结构以及当前版本。我们不会改变现有的数据结构,只是使用现有的数据结构作为创建新数据结构的基础。

只需复制即可对任何数据结构进行此操作。例如,考虑一些伪F#:

let array1 = [| 1, 2, 3, 4, 5 |]
let array2 = append 6 array1 // [| 1, 2, 3, 4, 5, 6 |]

要实现append函数,我们必须创建一个n+1大小的新数组,并使用array1的副本和要追加的元素填充它。

请注意这不是很有效,每个附加都需要n个副本并为整个结构分配内存。

请考虑我们定义一些类型:

type List<'a> = 
    |Empty
    |Cons of 'a * List<'a>

使用Cons案例,我们可以从旧列表和单个元素构建新列表。

考虑一下我们现在有一个包含100万个元素的列表:

let list1 = [1..1000000]
let list2 = Cons (0, list1) // [0..1000000]

在这种情况下,list2只是引用list1,不需要复制。因此,在列表开头之前是O(1)操作,尽管数据持久性,内存占用量仅随每个元素线性增长。

还有许多其他持久性数据结构,二叉树通常用于制作不可变集和字典。手指树可以作为Deques和Priority队列等结构的基础。

因此,简而言之,列表在函数式语言中被广泛使用,因为它们是一种简单,高效,持久的数据结构。