Có phải lập trình chức năng bỏ qua những lợi ích thu được từ các Tiêu chí được sử dụng trong việc phân tách các hệ thống thành các mô-đun (ẩn dữ liệu)?


27

Có một bài viết kinh điển có tên Về các tiêu chí sẽ được sử dụng trong việc phân tách các hệ thống thành các mô-đun mà tôi mới đọc lần đầu tiên. Nó có ý nghĩa hoàn hảo với tôi, và có lẽ là một trong những bài viết mà OOP dựa trên. Kết luận của nó:

Chúng tôi đã cố gắng chứng minh bằng các ví dụ này rằng hầu như luôn luôn không chính xác khi bắt đầu phân tách một hệ thống thành các mô-đun trên cơ sở sơ đồ. ... Mỗi mô-đun sau đó được thiết kế để ẩn quyết định như vậy với các mô-đun khác

Theo ý kiến ​​thiếu kinh nghiệm và thiếu kinh nghiệm của tôi, lập trình chức năng đưa ra lời khuyên hoàn toàn ngược lại với bài viết này. Sự hiểu biết của tôi là lập trình chức năng làm cho luồng dữ liệu thành ngữ. Dữ liệu được truyền từ chức năng này sang chức năng khác, mỗi chức năng đều nhận thức sâu sắc về dữ liệu và "thay đổi nó" trên đường đi. Và tôi nghĩ rằng tôi đã thấy một cuộc nói chuyện Rich Hickey nơi anh ấy nói về việc ẩn dữ liệu được đánh giá cao hoặc không cần thiết hoặc một cái gì đó, nhưng tôi không thể nhớ chắc chắn.

  1. Đầu tiên tôi muốn biết nếu đánh giá của tôi là chính xác. Liệu mô hình FP và bài viết này không đồng ý về mặt triết học?
  2. Giả sử họ không đồng ý, làm thế nào để FP "bù đắp" cho việc thiếu dữ liệu của mình? Có lẽ họ hy sinh việc ẩn dữ liệu nhưng có được X, Y và Z. Tôi muốn biết lý do tại sao X, Y và Z được coi là có lợi hơn so với ẩn dữ liệu.
  3. Hoặc, giả sử họ không đồng ý, có lẽ FP cảm thấy việc che giấu dữ liệu là xấu. Nếu vậy, tại sao nó nghĩ rằng ẩn dữ liệu là xấu?
  4. Giả sử họ đồng ý, tôi muốn biết việc triển khai ẩn dữ liệu của FP là gì. Rõ ràng để thấy điều này trong OOP. Bạn có thể có một privatetrường mà không ai ngoài lớp có thể truy cập. Không có sự tương tự rõ ràng về điều này với tôi trong FP.
  5. Tôi cảm thấy có những câu hỏi khác tôi nên hỏi nhưng tôi không biết tôi nên hỏi. Hãy trả lời những điều đó, quá.

Cập nhật

Tôi tìm thấy bài nói chuyện Neal Ford này có một slide rất phù hợp trong đó. Tôi sẽ nhúng ảnh chụp màn hình ở đây:

nhập mô tả hình ảnh ở đây


1
Tôi không thể trả lời câu hỏi đầy đủ, nhưng đối với (4), có các hệ thống mô-đun trong một số ngôn ngữ FP có thể cung cấp đóng gói.
Andres F.

@AresresF. ah vâng đó là sự thật. Tôi quên rằng Haskell có các mô-đun và bạn có thể ẩn các kiểu dữ liệu và chức năng trong đó. Có lẽ khi tôi nói FP tôi thực sự đang nói Clojure. Bạn có thể có các chức năng riêng tư và "trường" trong Clojure, nhưng tôi cảm thấy như đó là thành ngữ để làm cho dữ liệu của bạn hiển thị với mọi thứ và chuyển nó đi bất cứ đâu.
Daniel Kaplan

6
Những gì bạn thường làm là làm cho các kiểu của bạn hiển thị, nhưng ẩn các hàm tạo của bạn. Các loại trừu tượng này được thực hiện đặc biệt tốt bởi hệ thống mô-đun OCaml
Daniel Gratzer

6
Trong ngôn ngữ giống ML, không có quyền truy cập vào các hàm tạo có nghĩa là bạn không thể khớp mẫu với giá trị của loại đó để giải cấu trúc nó. Điều duy nhất bạn có thể làm với các giá trị đó là chuyển nó đến bất kỳ chức năng nào đã có sẵn. Đó là cùng một kiểu trừu tượng dữ liệu như được thực hiện trong, giả sử, C không có khái niệm hạng nhất về những gì là công khai hoặc riêng tư.
Luc Danton

1
@ SK-logic: Từ quan điểm "vấn đề biểu hiện", tiết lộ dữ liệu là tốt khi bạn muốn mở rộng với chức năng mới trong tương lai (và ổn với việc giữ dữ liệu cố định) và ẩn dữ liệu là tốt khi bạn muốn để mở rộng với các kiểu dữ liệu mới trong tương lai (với chi phí giữ giao diện chức năng cố định)
hugomg

Câu trả lời:


23

Bài viết mà bạn đề cập là về tính mô đun nói chung, và nó sẽ áp dụng như nhau cho các chương trình có cấu trúc, chức năng và hướng đối tượng. Tôi đã nghe về bài báo đó trước đây từ một người là một người OOP lớn, nhưng tôi đọc nó như một bài viết về lập trình nói chung, không phải là một cái gì đó cụ thể về OOP. Có một bài viết nổi tiếng về lập trình chức năng, Tại sao các vấn đề lập trình chức năng và câu đầu tiên của kết luận nêu rõ "Trong bài viết này, chúng tôi đã lập luận rằng tính mô đun là chìa khóa để lập trình thành công." Vì vậy, câu trả lời cho (1) là không.

Các chức năng được thiết kế tốt không giả định nhiều về dữ liệu của họ hơn mức cần thiết, vì vậy phần về "nhận thức sâu sắc về dữ liệu" là sai. (Hoặc ít nhất là sai như OOP. Bạn không thể lập trình nghiêm túc ở mức độ trừu tượng cao và bỏ qua tất cả các chi tiết mãi mãi trong bất kỳ mô hình nào. Cuối cùng, một số phần của chương trình thực sự cần biết về chi tiết cụ thể của dữ liệu.)

Ẩn dữ liệu là một thuật ngữ cụ thể OOP và nó không hoàn toàn giống với ẩn thông tin được thảo luận trong bài viết. Thông tin ẩn trong bài viết là về các quyết định thiết kế khó thực hiện hoặc có khả năng thay đổi. Không phải mọi quyết định thiết kế về định dạng dữ liệu đều khó hoặc có khả năng thay đổi và không phải mọi quyết định khó hoặc có khả năng thay đổi là về định dạng dữ liệu. Cá nhân, tôi không thể hiểu tại sao các lập trình viên OO muốn mọi thứ trở thành một đối tượng. Đôi khi, một cấu trúc dữ liệu đơn giản là tất cả những gì bạn cần.

Chỉnh sửa: Tôi tìm thấy một trích dẫn có liên quan từ một cuộc phỏng vấn với Rich Hickey .

Fogus: Theo ý tưởng đó, một số người ngạc nhiên về việc Clojure không tham gia vào việc đóng gói ẩn dữ liệu trên các loại của nó. Tại sao bạn quyết định từ bỏ ẩn dữ liệu?

Hickey: Chúng ta hãy rõ ràng rằng Clojure nhấn mạnh mạnh vào lập trình để trừu tượng hóa. Tại một số điểm, ai đó sẽ cần phải có quyền truy cập vào dữ liệu. Và nếu bạn có một khái niệm về riêng tư, bạn cần có những khái niệm tương ứng về đặc quyền và sự tin tưởng. Và điều đó thêm vào cả tấn sự phức tạp và ít giá trị, tạo ra sự cứng nhắc trong một hệ thống và thường buộc mọi thứ phải sống ở những nơi họ không nên đến. Điều này là thêm vào sự mất mát khác xảy ra khi thông tin đơn giản được đưa vào các lớp. Trong phạm vi dữ liệu là bất biến, có rất ít tác hại có thể đến từ việc cung cấp quyền truy cập, ngoài việc ai đó có thể phụ thuộc vào thứ gì đó có thể thay đổi. Chà, được thôi, mọi người làm điều đó mọi lúc trong cuộc sống thực, và khi mọi thứ thay đổi, họ thích nghi. Và nếu chúng hợp lý, họ biết khi nào họ đưa ra quyết định dựa trên điều gì đó có thể thay đổi mà họ có thể cần phải thích nghi trong tương lai. Vì vậy, đó là một quyết định quản lý rủi ro, tôi nghĩ các lập trình viên nên tự do thực hiện. Nếu mọi người không có sự nhạy cảm để mong muốn lập trình trừu tượng và cảnh giác với việc kết hôn với các chi tiết thực hiện, thì họ sẽ không bao giờ trở thành lập trình viên giỏi.


2
Các lập trình viên OO không muốn mọi thứ trở thành một đối tượng. Nhưng một số thứ (rất nhiều thứ) được hưởng lợi từ việc đóng gói. Tôi đang gặp khó khăn trong việc hiểu làm thế nào hoặc nơi câu trả lời của bạn thực sự giải quyết câu hỏi. Dường như chỉ khẳng định rằng khái niệm này không cụ thể đối với OOP và OOP có vấn đề khác, v.v. - bạn có thể cung cấp một ví dụ rõ ràng, ngay cả khi đó chỉ là một vài dòng mã giả? Hoặc một mô tả bảng trắng của một thiết kế có tính đến điều này? Hoặc bất cứ điều gì sẽ chứng minh các khẳng định ở đây?
Aaronaught

2
@Aaronaught: Tôi đã giải quyết nhiều (mặc dù không phải tất cả) các điểm nêu trong câu hỏi và tham khảo một bài viết về lập trình chức năng xem xét mô đun theo cách tương tự như bài báo trong câu hỏi. Ở một mức độ lớn, thực tế là khái niệm không cụ thể đối với OOP câu trả lời cho câu hỏi của anh ấy (trừ khi tôi hoàn toàn hiểu sai câu hỏi). Tôi thực sự đã không nói về OOP có vấn đề khác ở đây. Bạn có một điểm tốt về việc cung cấp một ví dụ; Tôi sẽ xem nếu tôi có thể đưa ra một cái tốt.
Michael Shaw

2
"Đôi khi, một cấu trúc dữ liệu đơn giản là tất cả những gì bạn cần". +1. Một cái gì đó OOP có ý nghĩa, đôi khi đó là FP.
Laurent Bourgault-Roy

1
@Aaronaught Câu trả lời này chỉ ra về tính mô đun (cả đóng gói và tái sử dụng) là một trong những mục tiêu của FP (như đã thảo luận trong "Tại sao các vấn đề lập trình chức năng"), do đó làm cho câu trả lời cho điểm (1) của câu hỏi là " Không".
Andres F.

2
@JimmyHoffa ẩn thông tin là một nguyên tắc lành mạnh ngay cả bên ngoài OO. Trong haskell, tôi vẫn muốn người dùng được phép làm việc với lượng kiến ​​thức tối thiểu về bất kỳ cấu trúc dữ liệu nào. Chắc chắn, có quyền truy cập vào nội bộ là ít nguy hiểm hơn vì không có gì là đột biến. Nhưng càng ít người dùng nhìn thấy về một mô-đun / cấu trúc dữ liệu / bất kỳ khái niệm trừu tượng nào, bạn càng nhận được nhiều cơ hội tái cấu trúc. Tôi không quan tâm nếu Bản đồ là cây nhị phân cân bằng hoặc chuột trong một hộp nhỏ trong máy tính của tôi. Đây là động lực chính đằng sau việc ẩn dữ liệu và nó có giá trị bên ngoài OO.
Simon Bergot

12

... Và có lẽ là một trong những bài viết mà OOP dựa trên.

Không thực sự, nhưng nó đã thêm vào cuộc thảo luận, đặc biệt với các học viên rằng, vào thời điểm đó, được đào tạo để phân hủy các hệ thống bằng cách sử dụng các tiêu chí đầu tiên mà anh mô tả trong bài báo.

Đầu tiên tôi muốn biết nếu đánh giá của tôi là chính xác. Liệu mô hình FP và bài viết này không đồng ý về mặt triết học?

Không. Ngoài ra, trong mắt tôi, mô tả của bạn về một chương trình FP trông như thế nào không khác với bất kỳ chương trình nào sử dụng các quy trình hoặc chức năng:

Dữ liệu được truyền từ chức năng này sang chức năng khác, mỗi chức năng đều nhận thức sâu sắc về dữ liệu và "thay đổi nó" trên đường đi.

... Ngoại trừ phần "thân mật", vì bạn có thể (và thường làm) có các chức năng hoạt động trên dữ liệu trừu tượng, chính xác để tránh sự thân mật. Do đó, bạn có một số quyền kiểm soát đối với "sự thân mật" đó và bạn có thể điều chỉnh nó theo cách bạn muốn, bằng cách thiết lập giao diện (ví dụ: các hàm) cho những gì bạn muốn ẩn.

Vì vậy, tôi thấy không có lý do tại sao chúng tôi sẽ không thể tuân theo các tiêu chí che giấu thông tin của Parnas bằng lập trình chức năng và kết thúc bằng việc thực hiện một chỉ số KWIC với lợi ích nhọn tương tự như cách thực hiện thứ hai của anh ấy.

Giả sử họ đồng ý, tôi muốn biết việc triển khai ẩn dữ liệu của FP là gì. Rõ ràng để thấy điều này trong OOP. Bạn có thể có một trường riêng mà không ai ngoài lớp có thể truy cập. Không có sự tương tự rõ ràng về điều này với tôi trong FP.

Đối với dữ liệu là mối quan tâm, bạn có thể xây dựng trừu tượng dữ liệu và trừu tượng loại dữ liệu bằng cách sử dụng FP. Bất kỳ trong số này ẩn các cấu trúc cụ thể và thao tác của các cấu trúc bê tông này bằng cách sử dụng các hàm làm trừu tượng.

CHỈNH SỬA

Có một số lượng lớn các xác nhận ở đây nói rằng "ẩn dữ liệu" trong bối cảnh của FP không hữu ích lắm (hoặc OOP-ish (?)). Vì vậy, hãy để tôi đóng dấu ở đây một ví dụ rất đơn giản và rõ ràng từ SICP:

Giả sử hệ thống của bạn cần phải làm việc với các số hữu tỷ. Một cách bạn có thể muốn biểu diễn chúng là một cặp hoặc một danh sách gồm hai số nguyên: tử số và mẫu số. Như vậy:

(define my-rat (cons 1 2)) ; here is my 1/2 

Nếu bạn bỏ qua việc trừu tượng hóa dữ liệu, rất có thể bạn sẽ nhận được tử số và mẫu số bằng cách sử dụng carcdr:

(... (car my-rat)) ; do something with the numerator

Theo cách tiếp cận này, tất cả các bộ phận của hệ thống thao túng các số hữu tỷ sẽ biết rằng một số hữu tỷ là một cons- chúng sẽ đánh conssố để tạo ra các số hữu tỷ và trích xuất chúng bằng cách sử dụng các toán tử danh sách.

Một vấn đề bạn có thể gặp phải là khi bạn cần giảm một dạng số hữu tỷ - những thay đổi sẽ được yêu cầu trên toàn bộ hệ thống. Ngoài ra, nếu bạn quyết định giảm thời gian tạo, bạn có thể thấy rằng việc giảm khi truy cập một trong các điều khoản hợp lý sẽ tốt hơn, mang lại sự thay đổi toàn diện khác.

Một vấn đề khác là nếu, theo giả thuyết, một đại diện thay thế cho chúng được ưa thích và bạn quyết định từ bỏ consđại diện - thay đổi toàn bộ quy mô một lần nữa.

Bất kỳ nỗ lực lành mạnh nào trong việc xử lý các tình huống này có thể sẽ bắt đầu che giấu sự đại diện của các lý trí đằng sau các giao diện. Cuối cùng, bạn có thể kết thúc với một cái gì đó như thế này:

  • (make-rat <n> <d>)trả về số hữu tỷ có tử số là số nguyên <n>và mẫu số của chúng là số nguyên <d>.

  • (numer <x>)trả về tử số của số hữu tỉ <x>.

  • (denom <x>)trả về mẫu số của số hữu tỷ <x>.

và hệ thống sẽ không còn (và không còn nữa) biết những gì hợp lý được tạo ra. Điều này là bởi vì cons, carcdrkhông phải là nội tại đối với các lý trí, nhưng make-rat, numerdenom . Tất nhiên, đây có thể dễ dàng là một hệ thống FP. Vì vậy, "ẩn dữ liệu" (trong trường hợp này, được gọi là trừu tượng hóa dữ liệu, hoặc nỗ lực đóng gói các biểu diễn và cấu trúc cụ thể) là một khái niệm có liên quan và một kỹ thuật được sử dụng và khám phá rộng rãi, cho dù trong bối cảnh của OO, lập trình chức năng hay bất cứ điều gì.

Và vấn đề là ... mặc dù người ta có thể cố gắng phân biệt giữa "loại ẩn" hoặc đóng gói mà họ đang làm (cho dù họ đang che giấu một quyết định thiết kế, hoặc cấu trúc dữ liệu hoặc thuật toán - trong trường hợp trừu tượng hóa thủ tục), tất cả chúng đều có cùng một chủ đề: chúng được thúc đẩy bởi một hoặc nhiều điểm mà Parnas đưa ra rõ ràng. Đó là:

  • Khả năng thay đổi: cho dù các thay đổi cần thiết có thể được thực hiện cục bộ hoặc được lan truyền qua hệ thống.
  • Phát triển độc lập: đến mức độ nào hai phần của hệ thống có thể được phát triển song song.
  • Tính toàn diện: cần biết bao nhiêu hệ thống để hiểu một trong các bộ phận của nó.

Ví dụ trên được lấy từ cuốn sách SICP vì vậy, để thảo luận và trình bày đầy đủ về các khái niệm này trong cuốn sách, tôi khuyên bạn nên kiểm tra chương 2 . Tôi cũng khuyên bạn nên làm quen với các kiểu dữ liệu trừu tượng trong ngữ cảnh của FP, điều này mang đến các vấn đề khác cho bảng.


Tôi đồng ý rằng việc ẩn dữ liệu có liên quan trong FP. Và, như bạn nói, có nhiều cách để đạt được điều này.
Andres F.

2
Bạn vừa nêu quan điểm của tôi rất hay: Bạn có các hàm này không ẩn dữ liệu, chúng là các biểu thức mô tả cách lấy dữ liệu, do đó có sự trừu tượng trong một biểu thức thay vì trường dữ liệu bạn không cần phải lo lắng về việc ẩn dữ liệu bằng cách tạo một số đối tượng phức tạp với các thành viên riêng hoặc bằng cách làm cho các giá trị khuyết điểm của bạn không thể truy cập được, các hoạt động tạo ra, truy xuất và tương tác với dữ liệu hợp lý được thể hiện do đó dữ liệu hợp lý thực tế không cần phải bị ẩn vì thay đổi dữ liệu sẽ không thay đổi biểu cảm của bạn
Jimmy Hoffa

8

Bạn tin rằng lập trình chức năng thiếu dữ liệu ẩn là sai. Nó chỉ cần một cách tiếp cận khác nhau để ẩn dữ liệu. Một trong những cách phổ biến nhất để ẩn dữ liệu trong lập trình chức năng là thông qua việc sử dụng các hàm đa hình có chức năng làm đối số. Ví dụ, chức năng này

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

chỉ có thể thấy cấu trúc ngoài cùng của dữ liệu (nghĩa là nó là một danh sách) nó không thể thấy bất cứ điều gì về dữ liệu mà danh sách chứa và chỉ có thể hoạt động trên dữ liệu thông qua chức năng duy nhất được truyền cho nó.

Hàm được truyền dưới dạng đối số tương tự như một phương thức công khai trên kiểu dữ liệu mà danh sách chứa. Nó cung cấp một cách thức hoạt động hạn chế trên dữ liệu, nhưng không làm lộ ra hoạt động bên trong của loại dữ liệu.


5

Tôi sẽ tấn công vào một chi ở đây và nói rằng khái niệm này không liên quan đến FP theo cách của nó trong OO.

tl; dr; Điểm ẩn của dữ liệu là đảm bảo các trách nhiệm được duy trì ở nơi chúng cần và bạn không có các diễn viên bên ngoài làm rối tung dữ liệu mà họ không có kiến ​​thức. Trong dữ liệu FP được tạo bởi các biểu thức và theo cách này, bạn không thể gây rối với dữ liệu vì đó không phải là thuộc tính có thể thay đổi nhiều như các phép tính có thể kết hợp làm thay đổi hoàn toàn quy tắc của trò chơi.


Theo kinh nghiệm của tôi với FP; được thừa nhận là không đáng kể, tôi có xu hướng tìm thấy một sự tương phản rõ rệt với OO trong những gì biểu thị mô hình dữ liệu tốt / phổ biến.

Sự tương phản này là trong OO nói chung, bạn mô hình hóa mọi thứ để thể hiện dữ liệu của bạn. Tương tự xe bắt buộc:

Ôi

  • Bạn có một chiếc xe Object, có thể che giấu chính xác các chi tiết về chiếc xe như việc triển khai AC (nó được điều khiển bằng dây đai hay điều khiển bằng áp suất không khí? Người tiêu dùng không cần phải biết, vì vậy hãy giấu nó).
  • Đối tượng xe hơi này có nhiều đặc tính và phương pháp mô tả tất cả các sự thật về chiếc xe cũng như những cách mà bạn có thể làm việc với một chiếc xe hơi.
  • Đối tượng ô tô này có các thuộc tính là các thành phần của ô tô ẩn xa hơn trên toàn bộ Xe thực hiện cụ thể của chúng và dữ liệu của chúng cho phép các thành phần của xe có thể hoán đổi cho nhau.

Điều cần lưu ý ở đây là khi bạn mô hình hóa mọi thứ theo định dạng OO, tất cả là về việc thể hiện mọi thứ dưới dạng Dữ liệu. Bạn có các đối tượng có thuộc tính, nhiều thuộc tính đó là các đối tượng có nhiều thuộc tính hơn. Bạn có một vài phương thức ở đây và có gắn liền với các đối tượng đó, nhưng tất cả những gì chúng thực sự thường là tạo ra các thuộc tính của các đối tượng theo cách này và một lần nữa, đó là mô hình hóa rất tập trung vào dữ liệu; đó là bạn mô hình hóa dữ liệu của mình để được tương tác với việc tập trung vào cấu trúc dữ liệu để cung cấp tất cả các điểm của dữ liệu của bạn để người tiêu dùng có thể thay đổi dữ liệu theo cách này.

Chi cục Kiểm lâm

  • Bạn có rất nhiều tính toán cho phép bạn mô tả các hành vi
  • Những biểu hiện hành vi này có liên quan theo cách có thể được dịch theo cách hành vi của ô tô liên quan đến nhau, chẳng hạn như xe có tăng tốc / giảm tốc, có hai hành vi đối nghịch nhau theo cách tương tự.

Sự khác biệt lớn giữa OO và FP liên tục gây ấn tượng với tôi là như tôi đã nói ở trên cách bạn mô hình hóa dữ liệu. Trong OO như đã đề cập ở trên, bạn mô hình hóa dữ liệu dưới dạng dữ liệu, trong FP bạn mô hình hóa dữ liệu dưới dạng tính toán, biểu thức, thuật toán, đó là về mô hình hóa các hoạt động của dữ liệu của bạn hơn là sự thật của dữ liệu. Hãy suy nghĩ về mô hình hóa dữ liệu cơ bản trong toán học, luôn luôn là về một phương trình có thể tạo ra dữ liệu của bạn, mô hình hóa dữ liệu của bạn là hoạt động gây ra nó, trái ngược với OO đang mô hình hóa để đưa ra cách thể hiện dữ liệu bạn có. Đó là phần lớn sự khác biệt giữa FP và OO.

Hãy nhớ rằng, trong một thời gian dài LISP, một trong những ngôn ngữ FP nền tảng, đã sống với một lượng rất nhỏ các kiểu dữ liệu nguyên thủy. Điều này hoạt động vì cách tiếp cận không phải là mô hình hóa các biểu diễn phức tạp của dữ liệu của bạn giống như các tính toán tạo và thể hiện các hành vi của hệ thống của bạn.

Khi tôi bắt đầu viết một số mã trong FP, tôi bắt đầu bằng cách viết mã làm một cái gì đó, như khi tôi bắt đầu viết mã trong OO, tôi bắt đầu bằng cách viết các mô hình mô tả một cái gì đó. Việc thực hiện mọi thứ được ẩn giấu trong FP bằng cách thể hiện, việc thực hiện mọi thứ được phơi bày trong OO bằng cách được mô tả với dữ liệu, che giấu giới hạn dữ liệu này cho biết.


Quay trở lại câu hỏi, FP nói gì về việc che giấu dữ liệu, liệu nó có đánh giá cao nó hay không đồng ý với nó hay không?

Tôi nói điều đó không quan trọng, trong OO, dữ liệu của bạn là can đảm và những phần quan trọng trong chương trình của bạn cần được ẩn để không bị can thiệp. Trong FP, sự can đảm và kiến ​​thức về hệ thống của bạn được ẩn giấu trong các thuật toán và tính toán thể hiện hệ thống. Đây là theo định nghĩa ít nhiều bất biến, cách duy nhất để đột biến các biểu thức tính toán là những thứ như macro, nhưng ngay cả khi đó, các định nghĩa đột biến của bạn là các biểu thức không thể được can thiệp thêm.


Điều này thật tuyệt vời, tôi thực sự rất thích đọc nó. Cảm ơn sự đóng góp của bạn
Chris McCall

5

Có một chút nghịch lý ở đây. Mặc dù lập trình chức năng tập trung vào, tốt, các chức năng và thường có các chức năng hoạt động trực tiếp trên các kiểu dữ liệu nguyên thủy, nhưng nó có xu hướng ẩn nhiều dữ liệu hơn so với lập trình hướng đối tượng.

Làm thế nào là như vậy? Hãy suy nghĩ về một giao diện OO đẹp ẩn dữ liệu cơ bản - có lẽ là các bộ sưu tập (Tôi đang cố gắng chọn một cái gì đó gần như phổ biến). Bạn có thể không cần biết loại cơ bản của các đối tượng trong bộ sưu tập hoặc loại đối tượng thực hiện bộ sưu tập, miễn là bạn biết bộ sưu tập thực hiện, giả sử, IEnumerable. Vì vậy, bạn có dữ liệu ẩn.

Trong lập trình chức năng, bạn có thể viết một hàm hoạt động hiệu quả với giao diện IEnumerable, nhưng hoạt động trên kiểu dữ liệu nguyên thủy (hoặc trên bất kỳ loại dữ liệu nào). Nhưng điều gì sẽ xảy ra nếu kiểu không bao giờ thực hiện các phương thức IEnumerable? Đây là chìa khóa, bạn luôn có thể có các "phương thức" tạo thành các phần cần thiết của "giao diện" là các tham số được truyền vào hàm của bạn. Hoặc bạn có thể đặt các chức năng cùng với dữ liệu và thực hiện mọi thứ theo cách giống như OO.

Lưu ý rằng một trong hai cách bạn không có bất kỳ dữ liệu ẩn nào ít hơn bạn có trong OO. Hàm chung của tôi hoạt động trên mọi loại rõ ràng không truy cập dữ liệu trong loại đó - điều đó xảy ra trong các hàm được truyền dưới dạng tham số cho hàm chung, nhưng hàm chung không bao giờ nhìn vào các hàm đó để xem dữ liệu.

Vì vậy, theo như quan điểm của bạn 1, tôi không nghĩ rằng FP và bài báo thực sự không đồng ý. Tôi không nghĩ rằng đặc tính của bạn về việc không che giấu dữ liệu là chính xác. Chắc chắn người ta có thể thực hiện thiết kế mà tác giả ưa thích trong FP, chắc chắn.

Theo như điểm 4 (2 và 3 không có ý nghĩa để trả lời cho những gì tôi đã nói cho điểm 1) thì nó khác nhau. Nó cũng thay đổi trong các ngôn ngữ OO và trong nhiều lĩnh vực riêng tư là theo quy ước chứ không phải theo ngôn ngữ.


Nói cách khác: trong lập trình chức năng, nhiều thứ bị "ẩn" theo mặc định, đơn giản là vì nó thậm chí không tồn tại! Chỉ có những thứ bạn rõ ràng đưa vào phạm vi là "không bị chặn".
leftaroundabout

3

Đầu tiên, cảm ơn vì liên kết đến bài viết tuyệt vời này, tôi đã không biết điều này cho đến nay và nó đã cho tôi một số ý kiến ​​tuyệt vời về một số điều mà tôi đã thảo luận với một số nhà thiết kế phần mềm khác từ cộng đồng trong những năm qua. Đây là ý kiến ​​của tôi về nó:

Đầu tiên tôi muốn biết nếu đánh giá của tôi là chính xác. Liệu mô hình FP và bài viết này không đồng ý về mặt triết học?

Thiết kế FP tập trung rất nhiều vào luồng dữ liệu (IMHO không quá tệ vì bài viết có thể ám chỉ). Nếu đây là một "bất đồng" hoàn toàn có thể tranh cãi.

Giả sử họ không đồng ý, làm thế nào để FP "bù đắp" cho việc thiếu dữ liệu của mình? Có lẽ họ hy sinh việc ẩn dữ liệu nhưng có được X, Y và Z. Tôi muốn biết lý do tại sao X, Y và Z được coi là có lợi hơn so với ẩn dữ liệu.

IMHO nó không bù. Xem bên dưới.

Hoặc, giả sử họ không đồng ý, có lẽ FP cảm thấy việc che giấu dữ liệu là xấu. Nếu vậy, tại sao nó nghĩ rằng ẩn dữ liệu là xấu?

Tôi không nghĩ rằng hầu hết người dùng hoặc nhà thiết kế của FP đều cảm thấy hoặc suy nghĩ theo cách này, xem bên dưới.

Giả sử họ đồng ý, tôi muốn biết việc triển khai ẩn dữ liệu của FP là gì. Rõ ràng để thấy điều này trong OOP. Bạn có thể có một trường riêng mà không ai ngoài lớp có thể truy cập. Không có sự tương tự rõ ràng về điều này với tôi trong FP.

Đây là điểm - có lẽ bạn đã thấy rất nhiều hệ thống OOP được triển khai theo cách phi chức năng mà bạn tin rằng OOP không hoạt động. Và đó là một sai lầm, IMHO OOP và FP chủ yếu là các khái niệm trực giao và bạn hoàn toàn có thể xây dựng các hệ thống OO chức năng, cung cấp cho bạn một câu trả lời rõ ràng cho câu hỏi của bạn. Việc thực hiện "đối tượng" cổ điển trong FP được thực hiện bằng cách sử dụng các bao đóng và nếu bạn muốn các đối tượng được sử dụng trong một hệ thống chức năng, điểm quan trọng là thiết kế chúng không thay đổi.

Vì vậy, để tạo các hệ thống lớn hơn, IMHO bạn có thể tạo các mô-đun, lớp và đối tượng bằng các khái niệm OO, chính xác theo cách được mô tả trong "Modularization 2" trong bài viết mà không cần rời khỏi "đường dẫn FP". Bạn sẽ sử dụng khái niệm mô-đun của ngôn ngữ FP yêu thích của bạn, làm cho tất cả các đối tượng của bạn trở nên bất biến và sử dụng "tốt nhất của cả hai thế giới".


3

TL; DR : Không

Liệu mô hình FP và bài viết này không đồng ý về mặt triết học?.

Không, nó không có. Lập trình chức năng là khai báo là "một phong cách xây dựng cấu trúc và các yếu tố của các chương trình máy tính, thể hiện logic của một tính toán mà không mô tả dòng điều khiển của nó." Nó ít hơn về việc tuân theo biểu đồ dòng chảy và giống như tạo ra các quy tắc cho phép dòng chảy phát sinh trên chính nó.

Lập trình thủ tục gần với mã hóa biểu đồ luồng hơn lập trình hàm. Nó tuân theo các biến đổi xảy ra và mã hóa các biến đổi đó thành các thủ tục được thực hiện theo thứ tự, giống hệt như luồng trong biểu đồ luồng mô tả.

Trong khi đó, việc thực hiện mô hình ngôn ngữ thủ tục của chương trình như một chuỗi các mệnh lệnh bắt buộc có thể thay đổi hoàn toàn trạng thái chia sẻ, thực thi mô hình ngôn ngữ lập trình chức năng như là sự đánh giá các biểu thức phức tạp chỉ phụ thuộc lẫn nhau về các đối số và giá trị trả về. Vì lý do này, các chương trình chức năng có thể có thứ tự thực thi mã tự do hơn và các ngôn ngữ có thể cung cấp ít quyền kiểm soát đối với thứ tự thực hiện các phần khác nhau của chương trình. (Ví dụ: các đối số cho một lời gọi thủ tục trong Lược đồ được thực thi theo thứ tự tùy ý.)

Ẩn dữ liệu

  • Lập trình hàm có các phương thức ẩn dữ liệu riêng của nó, ví dụ như nghĩ rằng đóng . Đó là dữ liệu ẩn bằng cách đóng gói trong một bao đóng. Các trường khó có thể trở thành bất kỳ dữ liệu riêng tư nào đã bị đóng do chỉ có việc đóng có tham chiếu đến dữ liệu và bạn không thể tham chiếu đến bên ngoài để đóng.
  • Một trong những lý do để ẩn dữ liệu là để ổn định giao diện lập trình bằng cách ẩn dữ liệu đột biến. Lập trình hàm không có dữ liệu đột biến, do đó nó không cần nhiều dữ liệu ẩn.

3
"Lập trình chức năng không có dữ liệu đột biến, do đó nó không cần nhiều dữ liệu ẩn." - đây là một khẳng định rất sai lệch. Bạn tự nói với mình (và tôi đồng ý) rằng một trong những lý do để đóng gói hành vi là để kiểm soát đột biến dữ liệu. Nhưng để kết luận rằng việc thiếu đột biến gần như làm cho việc đóng gói trở nên vô dụng là một sự kéo dài rất lớn. Các ADT và trừu tượng hóa dữ liệu nói chung có sức lan tỏa trong các tài liệu và hệ thống của FP.
Thiago Silva

Tôi chưa bao giờ nói nó "gần như đóng gói lại vô dụng". Đó là những suy nghĩ của bạn và của riêng bạn. Tôi đã nói rằng bạn không cần phải che giấu nhiều dữ liệu vì thiếu các biến đột biến. Điều này không làm cho việc đóng gói hoặc dữ liệu trở nên vô dụng, nó chỉ làm giảm việc sử dụng vì những trường hợp đó không tồn tại. Tất cả các trường hợp khác trong đó ẩn dữ liệu và đóng gói là hữu ích vẫn còn hiệu lực.
dietbuddha
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.