Tại sao liệt kê cấu trúc dữ liệu của sự lựa chọn trong các ngôn ngữ chức năng?


45

Hầu hết các ngôn ngữ chức năng sử dụng danh sách được liên kết làm cấu trúc dữ liệu bất biến chính. Tại sao danh sách, và không ví dụ như cây? Cây cũng có thể sử dụng lại các đường dẫn, và thậm chí cả danh sách mô hình.



10
@gnat - đây không phải là một bản sao của câu hỏi đó. Câu trả lời được chấp nhận và chính xác cho câu hỏi đó về cơ bản là "bởi vì danh sách liên kết không thay đổi cho phép chia sẻ đuôi giữa danh sách cập nhật và bản gốc", một câu trả lời được chỉ ra là một phần của nền tảng cho câu hỏi này ...
Jules

9
Một điểm cần làm rõ là "danh sách" (khái niệm lập trình trừu tượng) khác với "danh sách liên kết" (một cách thực hiện cụ thể của khái niệm đó), giống như đặc điểm kỹ thuật của ngôn ngữ lập trình khác với cách thực hiện. Câu hỏi "tại sao các ngôn ngữ chức năng sử dụng danh sách (khái niệm lập trình trừu tượng) làm cấu trúc dữ liệu chính của chúng?" tinh tế nhưng về cơ bản rất khác với câu hỏi "tại sao các triển khai chung của các ngôn ngữ chức năng X, Y, & Z sử dụng danh sách được liên kết làm cấu trúc dữ liệu chính của chúng?"
RM

I scala Vector (được triển khai dưới dạng cây) được ưu tiên hơn một chút so với List stackoverflow.com/questions/6928327/. Trong thực tế, hầu hết mọi người vẫn sử dụng Danh sách (từ những gì tôi đã thấy).
Akavall

Tôi đã thực hiện một số khóa học Lập trình chức năng ở Scala và sử dụng RẤT NHIỀU cây. Nó chỉ là danh sách đơn giản hơn cho các ví dụ. Cây được sử dụng cho các vấn đề hiệu suất. Bạn có thể tạo các cây không thể tái sử dụng một phần của các cây cũ hơn khi bạn thêm các yếu tố vào danh sách không thể thay đổi.
Borjab

Câu trả lời:


56

Bởi vì danh sách đơn giản hơn cây. (Bạn có thể thấy điều này một cách tầm thường bởi thực tế rằng một danh sách là một cây thoái hóa, trong đó mỗi nút chỉ có một con duy nhất.)

Danh sách khuyết điểm là cấu trúc dữ liệu đệ quy đơn giản nhất có thể có kích thước tùy ý.

Guy Steele lập luận trong quá trình thiết kế ngôn ngữ lập trình Pháo đài rằng đối với các tính toán song song lớn trong tương lai, cả cấu trúc dữ liệu và luồng điều khiển của chúng ta phải có hình cây với nhiều nhánh, không phải tuyến tính như hiện tại. Nhưng hiện tại, hầu hết các thư viện cấu trúc dữ liệu cốt lõi của chúng tôi được thiết kế với xử lý tuần tự, lặp lại (hoặc đệ quy đuôi, điều đó không thực sự quan trọng, chúng giống nhau), không phải xử lý song song.

Lưu ý rằng, ví dụ như trong Clojure, có cấu trúc dữ liệu được thiết kế dành riêng cho thế giới song song, phân tán, "mây" ngày nay, thậm chí các mảng (được gọi là vectơ trong Clojure), có lẽ là cấu trúc dữ liệu "tuyến tính" nhất trong số chúng, thực sự được triển khai như cây.

Vì vậy, trong ngắn hạn: một danh sách khuyết điểm là cấu trúc dữ liệu đệ quy liên tục đơn giản nhất có thể và không cần phải chọn một "mặc định" phức tạp hơn. Những thứ khác tất nhiên có sẵn dưới dạng tùy chọn, ví dụ Haskell có mảng, hàng đợi ưu tiên, bản đồ, heap, treap, cố gắng và mọi thứ bạn có thể tưởng tượng, nhưng mặc định là danh sách khuyết điểm đơn giản.


10
Đúng, vectơ Clojure được triển khai dưới dạng cây, nhưng lưu ý rằng chúng là các hàm băm được ánh xạ , không phải là nhị phân chuẩn của bạn data Tree a = Leaf a | Branch a (Tree a) (Tree a). Điều này củng cố lập luận "đơn giản" của bạn.
wchargein

1
Các vectơ bền bỉ của FWIW Clojure được triển khai khi (như @wchargein chỉ ra các cây có phần phức tạp) để truy cập nhanh (logarit với cơ sở lớn) và cập nhật các phần tử tùy ý, không thực sự cho hoạt động song song với nhau trình độ). Các ngôn ngữ FP khác đưa ra lựa chọn giống nhau (đôi khi với các loại cây khác nhau) khi chúng muốn cả hai loại đó (ví dụ như của Haskell Sequencehoặc Scala Vector), nhưng không sử dụng cây khi chúng chỉ cần đọc vì chúng có thể đạt được điều đó trong thời gian không đổi thực sự (ví dụ: Haskell's Vectorhoặc F # thông qua .Net's ImmutableArray)
badcook

1
Ví dụ: pmapping trên một vectơ trong Clojure vẫn truy cập từng phần tử một cách tuần tự; cấu trúc cây của vectơ thường được ẩn khỏi người dùng cuối.
badcook

5

Trên thực tế, những danh sách đó cây! Bạn có các nút có hai trường carcdr, có thể chứa nhiều nút hoặc lá như vậy. Điều duy nhất mà làm cho những cây vào danh sách, là quy ước để giải thích sự cdrliên kết như liên kết tới nút tiếp theo trong danh sách tuyến tính, và các carliên kết như giá trị của nút hiện hành.

Điều đó nói rằng, tôi đoán rằng sự phổ biến của các danh sách được liên kết trong lập trình chức năng có liên quan đến sự phổ biến của đệ quy trên phép lặp. Khi cấu trúc lặp duy nhất của bạn trong tay là đệ quy (đuôi-), bạn muốn các cấu trúc dữ liệu dễ sử dụng với điều đó; và danh sách liên kết là hoàn hảo cho điều đó.


5
điều đó phụ thuộc vào ngôn ngữ Chắc chắn, bạn có thể triển khai một cây trong các lượt thích LISP bằng cách sử dụng các ô khuyết điểm, nhưng trong Haskell, chẳng hạn, bạn sẽ cần một cấu trúc hoàn toàn riêng biệt. Và cũng lưu ý rằng hầu hết các ngôn ngữ chức năng có nhiều hơn các cấu trúc vòng lặp hơn đuôi đệ quy. Chẳng hạn, các thư viện lõi Haskell cung cấp các nếp gấp (trái và phải), quét, di chuyển trên cây, lặp lại các khóa và giá trị của bản đồ và nhiều cấu trúc chuyên môn khác. Chắc chắn, chúng được thực hiện với đệ quy đằng sau hậu trường, nhưng người dùng thậm chí không cần nghĩ về điều đó để làm cho chúng hoạt động.
Jules

@Jules Tuy nhiên, lập trình chức năng đã được phát triển và chịu ảnh hưởng lớn của các ngôn ngữ như LISP. Rõ ràng, có thể làm cho tất cả việc lặp lại danh sách này hiệu quả hơn bằng cách sử dụng các mảng dưới mui xe hoặc thêm đường cú pháp che giấu bản chất của một danh sách, nhưng lập trình chức năng thuần túy có thể làm được, và không cần. Ngoài ra, Haskell là một ngôn ngữ gần đây (trẻ hơn LISP 32 tuổi), bổ sung khá nhiều ý tưởng khác, đường cú pháp, v.v. vào phong cách chức năng thuần túy. Tôi nghĩ rằng, đánh giá lập trình chức năng bằng cách đánh giá Haskell giống như đánh giá các máy trộn bằng cách đánh giá thermomix ...
cmaster

2
@cmaster trong khi Haskell trẻ hơn, nó vẫn 27 tuổi và chịu ảnh hưởng của nhiều ngôn ngữ (bao gồm Python, Java và C # để đặt tên cho một số ít ảnh hưởng). Đánh giá lập trình chức năng của LISP giống như đánh giá lập trình mệnh lệnh của ALGOL - cả hai đều đi một chặng đường dài hơn là trở nên không thể nhận ra. ĐỒNG Ý. Lisp được cho là vẫn có liên quan nhưng tôi sẽ không coi đó là 'chính thống' và bỏ lỡ nhiều cái nhìn sâu sắc sau này bao gồm các loại ML.
Maciej Piechotka

1
Bạn không thể xử lý đệ quy các cây liên kết đơn lẻ hoặc lặp đi lặp lại mà không có ngăn xếp rõ ràng nếu bạn muốn chạm vào toàn bộ cây, vì vậy tôi không nghĩ đệ quy đuôi có liên quan gì đến nó.
k_g

@MaciejPiechotka Không thể xem Python, Java hay C # là ngôn ngữ chức năng, chúng là bắt buộc và thêm một vài tính năng được lấy cảm hứng từ lập trình chức năng. Một khi bạn đã thay đổi trạng thái, bạn chắc chắn bên trong miền bắt buộc, không phải lập trình chức năng. Tuy nhiên, tôi đồng ý với bạn rằng LISP chắc chắn không phải là chủ đạo.
cmaster
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.