Tại sao chúng ta sử dụng các cấu trúc dữ liệu liên tục trong lập trình chức năng?


22

Lập trình hàm sử dụng các cấu trúc dữ liệu liên tục và các đối tượng bất biến. Câu hỏi của tôi là tại sao điều quan trọng là phải có cấu trúc dữ liệu như vậy ở đây? Tôi muốn hiểu ở mức độ thấp những gì sẽ xảy ra nếu cấu trúc dữ liệu không liên tục? Chương trình sẽ sụp đổ thường xuyên hơn?


có một cuộc thảo luận mở rộng khá tốt về vấn đề này trong abelson & sussman, cấu trúc và giải thích các chương trình máy tính
vzn

Câu trả lời:


19

Khi bạn làm việc với các đối tượng dữ liệu bất biến, các hàm có thuộc tính mà mỗi khi bạn gọi chúng với cùng một đầu vào, chúng sẽ tạo ra các đầu ra giống nhau. Điều này giúp dễ dàng khái niệm hóa các tính toán và làm cho chúng đúng. Nó cũng làm cho chúng dễ dàng hơn để kiểm tra.

Đó chỉ là một sự khởi đầu. Vì toán học đã làm việc lâu dài với các chức năng, có rất nhiều kỹ thuật lý luận mà chúng ta có thể mượn từ toán học, và sử dụng chúng cho lý luận nghiêm ngặt về các chương trình. Lợi thế quan trọng nhất theo quan điểm của tôi là các hệ thống loại cho các chương trình chức năng được phát triển tốt. Vì vậy, nếu bạn mắc lỗi ở đâu đó, khả năng rất cao là nó sẽ hiển thị dưới dạng không khớp. Vì vậy, các chương trình chức năng đánh máy có xu hướng đáng tin cậy hơn nhiều so với các chương trình bắt buộc.

Ngược lại, khi bạn làm việc với các đối tượng dữ liệu có thể thay đổi, trước tiên, bạn có tải nhận thức về việc ghi nhớ và quản lý nhiều trạng thái mà đối tượng trải qua trong quá trình tính toán. Bạn phải cẩn thận để làm mọi thứ theo đúng thứ tự, đảm bảo rằng tất cả các thuộc tính bạn cần cho một bước cụ thể được thỏa mãn tại thời điểm đó. Rất dễ mắc sai lầm và các hệ thống loại không đủ mạnh để bắt những lỗi đó.

Toán học không bao giờ làm việc với các đối tượng dữ liệu có thể thay đổi. Vì vậy, không có kỹ thuật lý luận chúng ta có thể mượn từ họ. Có rất nhiều kỹ thuật của chúng tôi được phát triển trong Khoa học Máy tính, đặc biệt là Logic Floyd-Hoare . Tuy nhiên, đây là những thử thách khó hơn để thành thạo hơn các kỹ thuật toán học tiêu chuẩn, hầu hết học sinh không thể xử lý chúng, và vì vậy chúng hiếm khi được dạy.

Để biết tổng quan nhanh về cách hai mô hình khác nhau, bạn có thể tham khảo một vài hướng dẫn đầu tiên về ghi chú bài giảng của tôi về Nguyên tắc Ngôn ngữ lập trình .


Điều này rất có ý nghĩa với tôi. Cảm ơn đã chia sẻ PPT của bạn. Bạn có chia sẻ các bản ghi video giống nhau không?
gpuguy

@gpuguy. Tôi không sử dụng powerpoint nhiều như vậy. Bảng trắng là phương tiện yêu thích của tôi. Nhưng bản phát nên khá dễ đọc.
Uday Reddy

Toán học +1 không bao giờ làm việc với các đối tượng dữ liệu có thể thay đổi. Ngoài ra các liên kết đến ghi chú bài giảng của bạn.
Guy Coder

15

Nó là dễ dàng hơn để làm việc với một cách chính xác các cấu trúc dữ liệu liên tục hơn là làm việc với các cấu trúc dữ liệu có thể thay đổi. Điều này, tôi sẽ nói, là lợi thế chính.

Tất nhiên, về mặt lý thuyết, bất cứ điều gì chúng ta làm với các cấu trúc dữ liệu liên tục, chúng ta cũng có thể làm với các cấu trúc có thể thay đổi và ngược lại. Trong nhiều trường hợp, cấu trúc dữ liệu liên tục phải chịu thêm chi phí, thường là do các phần của chúng phải được sao chép. Những cân nhắc này sẽ khiến cấu trúc dữ liệu liên tục kém hấp dẫn hơn 30 năm trước khi siêu máy tính có bộ nhớ ít hơn điện thoại di động của bạn. Nhưng ngày nay, những vướng mắc chính trong sản xuất phần mềm dường như là thời gian phát triển và chi phí bảo trì. Do đó, chúng tôi sẵn sàng hy sinh một số hiệu quả trong thực thi để đạt được hiệu quả trong phát triển.

Tại sao nó dễ dàng hơn để sử dụng các cấu trúc dữ liệu liên tục? Bởi vì con người rất tệ trong việc theo dõi răng cưa và các loại tương tác bất ngờ khác giữa các phần khác nhau của chương trình. Họ tự động nghĩ rằng bởi vì hai thứ được gọi xysau đó không có gì trong commmon. Hơn tất cả, phải nỗ lực để tìm ra rằng "ngôi sao buổi sáng" và "ngôi sao buổi tối" thực sự giống nhau. Tương tự, rất dễ quên rằng cấu trúc dữ liệu có thể thay đổi do các luồng khác đang làm việc với nó hoặc vì chúng tôi đã gọi một phương thức xảy ra để thay đổi cấu trúc dữ liệu, v.v. Nhiều trong số những lo ngại này không xuất hiện khi chúng tôi làm việc với cấu trúc dữ liệu liên tục.

Cấu trúc dữ liệu bền bỉ cũng có những lợi thế kỹ thuật khác. Nó thường dễ dàng hơn để tối ưu hóa chúng. Ví dụ: bạn luôn tự do sao chép cấu trúc dữ liệu liên tục vào một số nút khác trong đám mây của mình nếu muốn, không phải lo lắng về việc đồng bộ hóa.


Khi nó có rất nhiều lợi thế thì tại sao không sử dụng cấu trúc dữ liệu liên tục trong các ngôn ngữ bắt buộc?
gpuguy

4
Có lẽ bạn sẽ sớm hỏi "Tại sao phải sử dụng ngôn ngữ bắt buộc?"
Andrej Bauer

4
Nhưng nghiêm túc, có những cơ sở dữ liệu khó thay thế bằng các chương trình liên tục, ví dụ các chương trình xử lý số sử dụng mảng và ma trận nhanh hơn nhiều với cấu trúc dữ liệu truyền thống vì phần cứng được tối ưu hóa cho loại điều đó.
Andrej Bauer

1
@gpuguy. Cấu trúc dữ liệu liên tục có thể, và nên được sử dụng trong các ngôn ngữ bắt buộc, bất cứ khi nào chúng có thể áp dụng và phù hợp. Để có thể sử dụng chúng, ngôn ngữ nên hỗ trợ quản lý bộ nhớ dựa trên bộ sưu tập rác. Nhiều ngôn ngữ hiện đại có: Java, C #, Scala, Python, Ruby, Javascript, v.v.
Uday Reddy

Có thể cho rằng, một lợi thế lớn là giao diện trừu tượng hơn so với các cơ sở dữ liệu có thể thay đổi. Bạn có thể thay đổi công cụ dưới mui xe (cf bất biến so với tính toàn vẹn chính xác) nhưng không phải.
Raphael

2

Thêm vào câu trả lời của người khác và củng cố cách tiếp cận toán học, lập trình hàm cũng có một sức mạnh tổng hợp tốt với Đại số quan hệ và Kết nối Galois.

Điều này cực kỳ hữu ích trong lĩnh vực Phương thức chính thức.
Ví dụ:

  • Bằng chứng chính thức trong xác minh chương trình được đơn giản hóa với Kiểm tra tĩnh mở rộng;
  • Một số tính chất từ ​​Đại số quan hệ rất hữu ích trong việc giải SAT, với các công cụ như Alloy;
  • Kết nối Galois cho phép một cách tiếp cận tính toán đến đặc tả phần mềm, như đã thấy trong blog này , với một tài liệu tham khảo đến một bài báo , của Shin-Cheng Mu và José Nuno Oliveira.
  • Kết nối Galois (và Lập trình chức năng) có thể được sử dụng trong Thiết kế theo kiểu Hợp đồng, vì chúng là một khái niệm tổng quát hơn Hoare Logic.

Thí dụ

{p}P{q}[P]ϕpϕq[P]

  • [P]P
  • ϕpϕq)pq

Cách tiếp cận này cũng cho phép tính toán trước điều kiện yếu nhất và tính toán sau điều kiện mạnh nhất , có ích trong một số tình huống.


2

Tôi muốn hiểu ở mức độ thấp những gì sẽ xảy ra nếu cấu trúc dữ liệu không liên tục?

Chúng ta hãy xem một trình tạo số giả ngẫu nhiên với một không gian trạng thái khổng lồ (như " Mersenne twister " với trạng thái 2450 byte) dưới dạng cấu trúc dữ liệu. Chúng tôi không thực sự muốn sử dụng bất kỳ số ngẫu nhiên nào nhiều hơn một lần, vì vậy dường như có rất ít lý do để thực hiện điều này như một cấu trúc dữ liệu liên tục không thay đổi. Bây giờ hãy hỏi bên ngoài những gì có thể sai trong mã sau đây:

mt_gen = CreateMersenneTwisterPRNGen(seed)
integral = MonteCarloIntegral_Bulk(mt_gen) + MonteCarloIntegral_Boundary(mt_gen)

Hầu hết các ngôn ngữ lập trình không chỉ định thứ tự MonteCarloIntegral_BulkMonteCarloIntegral_Boundarysẽ được đánh giá. Nếu cả hai đều tham chiếu đến mt_gen có thể thay đổi làm đối số, kết quả của tính toán này có thể phụ thuộc vào nền tảng. Tệ hơn nữa, có thể có các nền tảng mà kết quả không thể lặp lại ở tất cả các lần chạy khác nhau.

Người ta có thể thiết kế một cấu trúc dữ liệu có thể thay đổi hiệu quả cho mt_gen sao cho bất kỳ sự xen kẽ nào của việc thực hiện MonteCarloIntegral_BulkMonteCarloIntegral_Boundarysẽ cho kết quả "chính xác", nhưng nói chung, một sự xen kẽ khác nhau sẽ dẫn đến một kết quả "chính xác" khác. Không tái sản xuất này làm cho chức năng tương ứng "không trong sạch", và cũng dẫn đến một số vấn đề khác.

Không thể lặp lại có thể tránh bằng cách thực thi một lệnh thực hiện tuần tự cố định. Nhưng trong trường hợp đó, mã có thể được sắp xếp theo cách mà chỉ một tham chiếu duy nhất đến mt_gen có sẵn tại bất kỳ thời điểm nào. Trong ngôn ngữ lập trình chức năng được gõ, các loại duy nhất có thể được sử dụng để thực thi ràng buộc này, do đó cho phép cập nhật có thể thay đổi an toàn trong bối cảnh ngôn ngữ lập trình chức năng thuần túy. Tất cả điều này nghe có vẻ hay và bảnh bao, nhưng ít nhất trong lý thuyết mô phỏng Monte Carlo là song song đáng xấu hổvà "giải pháp" của chúng tôi vừa phá hủy tài sản này. Đây không chỉ là một vấn đề lý thuyết, mà là một vấn đề thực tế rất thực tế. Tuy nhiên, chúng tôi phải sửa đổi (chức năng được cung cấp bởi) trình tạo số giả ngẫu nhiên của chúng tôi và chuỗi số ngẫu nhiên mà nó tạo ra và không có ngôn ngữ lập trình nào có thể tự động làm điều này cho chúng tôi. (Tất nhiên chúng ta có thể sử dụng một thư viện số giả ngẫu nhiên khác đã cung cấp các chức năng cần thiết.)

Ở mức độ thấp, các cấu trúc dữ liệu có thể thay đổi dễ dẫn đến không thể lặp lại (và do đó không có tạp chất), nếu thứ tự thực hiện không tuần tự và cố định. Một chiến lược bắt buộc điển hình để giải quyết các vấn đề này là có các giai đoạn liên tiếp với thứ tự thực hiện cố định, trong đó các cấu trúc dữ liệu có thể thay đổi được thay đổi và các giai đoạn song song với thứ tự thực hiện tùy ý, trong đó tất cả các cấu trúc dữ liệu có thể thay đổi được chia sẻ không đổi.


Andrej Bauer đưa ra vấn đề răng cưa cho các cấu trúc dữ liệu có thể thay đổi. Thật thú vị, các ngôn ngữ mệnh lệnh khác nhau như Fortran và C có các giả định khác nhau về việc đặt bí danh cho phép của các đối số hàm và hầu hết các lập trình viên đều không biết rằng ngôn ngữ của họ có mô hình răng cưa nào cả.

Tính bất biến và giá trị ngữ nghĩa có thể được đánh giá hơi cao. Điều quan trọng hơn là hệ thống loại và khung logic (như mô hình máy trừu tượng, mô hình bí danh, mô hình đồng thời hoặc mô hình quản lý bộ nhớ) của ngôn ngữ lập trình của bạn cung cấp đủ hỗ trợ để làm việc "an toàn" với dữ liệu "hiệu quả" cấu trúc. Việc giới thiệu "di chuyển ngữ nghĩa" cho C ++ 11 có thể trông giống như một bước lùi khổng lồ về độ tinh khiết và "an toàn" từ quan điểm lý thuyết, nhưng trên thực tế thì ngược lại. Hệ thống loại và khung logic của ngôn ngữ đã được mở rộng để loại bỏ những phần nguy hiểm lớn liên quan đến ngữ nghĩa mới. (Và ngay cả khi các cạnh gồ ghề vẫn còn, điều này không có nghĩa là điều này không thể được cải thiện bởi "tốt hơn"


Uday Reddy đưa ra vấn đề rằng toán học không bao giờ hoạt động với các đối tượng dữ liệu có thể thay đổi và các hệ thống loại cho các chương trình chức năng được phát triển tốt cho các đối tượng dữ liệu bất biến. Điều này khiến tôi nhớ đến lời giải thích của Jean-Yves Girard rằng toán học không được sử dụng để làm việc với các vật thể thay đổi, khi anh ta cố gắng thúc đẩy logic tuyến tính.

Người ta có thể hỏi làm thế nào để mở rộng hệ thống loại và khung logic của các ngôn ngữ lập trình chức năng để cho phép làm việc "an toàn" với các cấu trúc dữ liệu không liên tục "hiệu quả" có thể thay đổi. Một vấn đề ở đây có thể là logic cổ điển và đại số boolean có thể không phải là khung logic tốt nhất để làm việc với các cấu trúc dữ liệu có thể thay đổi. Có lẽ logic tuyến tính và đơn sắc giao hoán có thể phù hợp hơn cho nhiệm vụ đó? Có lẽ tôi nên đọc những gì Philip Wadler nói về logic tuyến tính như hệ thống kiểu cho các ngôn ngữ lập trình chức năng? Nhưng ngay cả khi logic tuyến tính không thể giải quyết vấn đề này, điều đó không có nghĩa là hệ thống loại và khung logic của ngôn ngữ lập trình chức năng không thể được mở rộng để cho phép "an toàn" và "hiệu quả"


@DW Có lẽ bạn đúng khi câu trả lời này không phải là câu trả lời độc lập. Nó hiện chỉ mở rộng trên một số điểm nhất định được nêu ra trong các câu trả lời của Uday Reddy và Andrej Bauer. Tôi nghĩ rằng tôi có thể sửa đổi nó thành độc lập và trả lời trực tiếp "Tôi muốn hiểu ở mức độ thấp những gì sẽ xảy ra nếu cấu trúc dữ liệu không liên tục?" một phần của câu hỏi Tôi sẽ xem xét một trình tạo số giả ngẫu nhiên với không gian trạng thái lớn (như "Mersenne twister" với trạng thái 2450 byte) như một cấu trúc dữ liệu và giải thích những điều có thể sai.
Thomas Klimpel

@DW Tôi không cảm thấy rằng bất kỳ câu trả lời cho câu hỏi này thực sự trả lời câu hỏi. Cụ thể, không có gì nhiều về cấu trúc dữ liệu liên tục thực sự là gì (ngoài việc không thay đổi) và cách chúng được thực hiện.
Guildenstern
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.