Có phải lập trình chức năng thêm phức tạp trong mã? [đóng cửa]


17

Trong cả năm qua tôi đã được viết mã Scala (đến từ nền Java). Tôi thực sự thích cách bạn có thể tạo mã đơn giản và gọn gàng hơn, với các vals, lớp trường hợp, hàm map / bộ lọc / lambda, hàm ý và kiểu suy luận. Tôi đã sử dụng nó chủ yếu cho một ứng dụng dựa trên Akka .

Năm nay tôi tham gia một dự án Scala với một nhóm mới, người thực sự thích lập trình chức năng. Họ sử dụng rất nhiều Scalaz và mã được lấp đầy ở khắp mọi nơi với các ứng dụng, giới hạn bối cảnh, độc giả / nhà văn / nhà nước, thậm chí phương thức chính được "bọc" trong một đơn nguyên I / O. Lý do của họ là điều này làm cho trình biên dịch "làm việc cho chúng tôi" khi khẳng định rằng mã là chính xác và mỗi hàm không có tác dụng phụ.

Mặc dù vậy, theo quan điểm của tôi, tất cả cú pháp này thực sự cản trở logic kinh doanh. Chẳng hạn, một loại "MyBusinessObject" cũng tốt, cũng như các loại như "Danh sách [MyBusinessObject]", "Tùy chọn [MyBusinessObject]" hoặc thậm chí "Tương lai [MyBusinessObject]". Chúng đều có một ý nghĩa và mục đích rõ ràng. Mặt khác, mã như:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

nó có làm tăng thêm sự phức tạp cho chương trình không, hay chỉ là tôi không quen với cách lập trình này?


6
Câu hỏi khách quan của bạn là gì?
Deer Hunter

1
Có vẻ như nó dẫn đến một tấn mã với một hoặc hai tên biến chữ cái. Hình như APL một chút. Đó không phải là một bổ sung.
user949300

3
Tôi bắt đầu chơi với Haskell năm ngoái. Nó trông cực kỳ phức tạp vào thời điểm đó, khi tôi không hiểu các khái niệm như cà ri, functor, monad, v.v. Haskell tương tự như Scalaz ở chỗ nó có rất nhiều chức năng ngắn, tượng trưng, >>=<$>không có nghĩa gì cho đến khi bạn biết những gì họ làm. Sau khi biết ý nghĩa của chúng, tuy nhiên, bây giờ chúng đọc rất tự nhiên và nhanh chóng với tôi. Không thực sự là một câu trả lời, chỉ là kinh nghiệm khách quan của tôi với những thứ như thế này. Tôi cũng sử dụng Scala, nhưng không có kinh nghiệm với thư viện Scalaz.
KChaloux

3
Bạn chỉ không quen thuộc với các thành ngữ. @ user949300 biến ngắn không thực sự là vấn đề đối với nhiều mã chức năng (hãy nghĩ về các quy ước kiểu toán học!). Đồng thời đọc blog của Tony Morris để thảo luận sâu hơn về ý nghĩa tốt hơn truyền tải ý nghĩa, loại hoặc tên biến dài.
Andres F.

3
@ user949300: tên biến ngắn được ưa thích cục bộ, đó là giống nhau trong thế giới chức năng và mệnh lệnh (bạn sẽ không viết for(i=0; i<7; ++i) { trivialOperation(i); }với một số trivialOperationCountbiến khó xử , phải không?) Bây giờ, ngôn ngữ lập trình chức năng với khớp mẫu đôi khi sẽ giới thiệu thêm một số biến trong đó bạn 'Chỉ cần viết ra các cuộc gọi phương thức truy cập trong OO. Kết quả nói chung ngắn gọn hơn; có lẽ ít tự giải thích hơn, nhưng việc tra cứu khai báo dữ liệu thường làm cho nó rõ ràng nhanh chóng. Gõ tĩnh giúp ích rất nhiều, nó không giống như trong APL.
leftaroundabout

Câu trả lời:


37

Điều này không liên quan gì đến lập trình chức năng - bạn có thể tìm thấy loại tình huống này trong bối cảnh của bất kỳ ngôn ngữ lập trình nào khác - các nhà phát triển yêu thích cấu trúc nâng cao của ngôn ngữ "của họ" đến mức họ bỏ qua mọi ý nghĩa thông thường về khả năng đọc và giữ mọi thứ đơn giản. Tôi đã gặp một tình huống như vậy trong C, C ++, Perl, Java, C #, Basic và các ngôn ngữ phi chức năng khác. Đó không phải là lập trình chức năng làm tăng thêm độ phức tạp cho mã - lập trình viên làm.

Đừng hiểu sai ý tôi, tôi không khuyên bạn nên tránh các tính năng ngôn ngữ nâng cao - nhưng điều quan trọng là tìm được sự cân bằng phù hợp trong bối cảnh cụ thể. Khi viết một thư viện chung để sử dụng> 100.000 nhà phát triển trên toàn thế giới, có nhiều biện pháp khác nhau để áp dụng như khi bạn viết một trình tạo báo cáo riêng cho văn phòng địa phương.


7
Nó cũng có rất nhiều để làm với cộng đồng. Đối với nhà phát triển có nền tảng Java hoặc C #, mã này hầu như không thể hiểu được (và cộng đồng của anh ấy / cô ấy cũng sẽ không hiểu nó). Nhưng nếu bạn viết Haskell, chẳng hạn, và bạn không sử dụng các đơn nguyên, ứng dụng, functor, v.v., bạn đang gây trở ngại cho cộng đồng ngôn ngữ đó. "Tính tự nhiên" của mã không phải là vốn có, mà liên quan đến cộng đồng và các thông lệ đã được thiết lập.
Andres F.

1
Điều này là khó thấy bởi vì hầu hết chúng ta đến từ những nền tảng bắt buộc, đôi khi khiến chúng ta đưa ra những giả định sai về những gì tự nhiên.
Andres F.

Chỉ cần nhìn vào thư viện SLT C ++, có thể được viết để dễ đọc hơn rất nhiều cho người nghiệp dư
ratchet freak

@ratchetfreak: Tôi đoán bạn có nghĩa là STL. Tôi nghĩ rằng đây là một ví dụ rất tốt (và thực sự, tôi đã nghĩ đến điều này trong câu trả lời của mình). Sử dụng lập trình meta mẫu có ý nghĩa rất lớn khi bạn là lập trình viên STL, bởi vì nó làm cho STL có thể tái sử dụng nhiều hơn. Và những người phải duy trì mã đó thường được sử dụng để tạo mẫu siêu lập trình. Sử dụng siêu lập trình mẫu theo kiểu STL trong suốt ứng dụng kinh doanh tiêu chuẩn của bạn có thể dễ dàng dẫn đến mã quá phức tạp, khó duy trì. Người ta chắc chắn có thể tìm thấy (hiếm) trường hợp TMP vẫn ổn ngay cả trong ứng dụng kinh doanh, của cours.
Doc Brown

@DocBrown yeah mắc chứng khó đọc không đúng lúc, nhưng thành thật mà nói nếu tôi có một nửa tâm trí (và nhiều thời gian hơn bây giờ) tôi có thể viết lại nhiều cơ quan chức năng để dễ đọc hơn nhiều.
ratchet freak

7

Tôi sẽ nói rằng bạn không quen với cách họ mã hóa ít nhất là một phần của bức tranh. Tôi cũng ở trong hoàn cảnh tương tự như bạn (từ C # vào F # và làm việc với những người có nền tảng Haskell), và trong khi tôi thấy đó là một trải nghiệm thú vị, tôi có những khoảnh khắc khi tôi đập đầu vào tường, gỡ rối đặc biệt là thành phần chức năng không có điểm phức tạp chỉ để hiểu được những gì đang diễn ra ở đó. Đó là một điều văn hóa.

Về việc mã đặc biệt này có làm tăng thêm độ phức tạp cho chương trình hay không - tôi không biết. Đồng ý rằng một đoạn mã chung có thể phức tạp. Nhưng đó là một tiện ích, không phải là một phần của logic kinh doanh. Nếu bạn muốn biết liệu nó làm cho cơ sở mã phức tạp hơn hay đơn giản hơn, bạn sẽ phải tưởng tượng nó sẽ trông như thế nào nếu không có đoạn mã đó. Đó thường là trường hợp với các cấu trúc chung như vậy mà chúng phức tạp, nhưng nó phức tạp mà bạn có thể phù hợp trên một màn hình. Đồng thời họ làm cho toàn bộ cơ sở mã đơn giản hơn một chút. Điều này đặc biệt là trường hợp với các đơn nguyên.

Sau đó, một lần nữa, nó cũng có thể là một trường hợp 'nghệ thuật vì nghệ thuật', như @Doc Brown gợi ý. Không thể loại trừ nó.


5

Tôi sẽ lập luận rằng trong lập trình chức năng nói chung làm giảm sự phức tạp bằng cách loại bỏ trạng thái có thể thay đổi, do đó giảm số lượng các trường hợp phải được xem xét khi cố gắng hiểu cách một phần của mã hoạt động.

Tuy nhiên, lập trình chức năng làm cho mức độ trừu tượng hóa cao hơn có thể, và trong khi mã trừu tượng cao có thể cực kỳ hữu ích thì cũng có thể khó hiểu vì theo định nghĩa, nó được tách ra khỏi bối cảnh mà bạn thường sử dụng để hướng dẫn sự hiểu biết của mình. Nhận xét của bạn "Tất cả đều có ý nghĩa và mục đích rõ ràng" về các đối tượng kinh doanh chắc chắn là đúng, nhưng thực sự là một sự phản ánh của thực tế rằng logic đó rất cụ thể cho một nhu cầu và bối cảnh bạn đã hiểu. Sự tồn tại của một cấu trúc như Monad cho phép bạn tạo ra thứ gì đó rất hữu ích với ít nỗ lực, nhưng trang web tràn ngập các trang cố gắng giải thích Monad là gì. Đó là sự trừu tượng cho bạn.

Ngoài ra, Scalaz được viết bởi những người đã ăn và thở FP trong một thời gian dài; họ muốn mang chức năng có sẵn trong Haskell cho Scala. Làm như vậy họ không cố gắng để được sư phạm. Scalaz sử dụng từ vựng và văn phong có vẻ rõ ràng và dễ hiểu đối với các tác giả nhưng xa lạ với những người không quen biết. Các phương pháp gây bối rối cho phần còn lại của chúng tôi dường như quá rõ ràng đối với các tác giả, với nền tảng Haskell của họ, mà họ thậm chí không đảm bảo nhận xét.

Hơn nữa, vì ngôn ngữ lập trình chức năng, Scala có một số thiếu sót (một phần vì JVM có những thiếu sót) đã buộc các tác giả của Scalaz phải viết mã xấu hơn trong một số trường hợp. Ví dụ, việc thiếu loại bỏ cuộc gọi đuôi nói chung buộc phải sử dụng trampolines trong một số mã và việc thiếu một "hệ thống loại" có thể làm phức tạp chữ ký loại.

Và cuối cùng, Scalaz sử dụng chính nó. Điều đó có thể được coi là một dấu hiệu cho sức mạnh của nó, nhưng đối với người không quen biết, nó có thể biến nguồn thành một câu đố - bất kỳ đoạn mã ngẫu nhiên nào bạn nhìn vào đều có khả năng sử dụng một thứ khác có vẻ xa lạ với bạn.

Treo ở đó. Và điều này có thể giúp.


-4

Nó có làm tăng thêm sự phức tạp cho chương trình không, hay chỉ là bạn chưa quen với cách lập trình này?

Tại sao bạn nghĩ những khả năng này không giống nhau?

Mã được viết tốt có thể được đọc bởi những người không quen thuộc với ngôn ngữ lập trình cụ thể. Một số ngôn ngữ (BASIC, Pascal, v.v.) có thể được đọc và hiểu bởi những đứa trẻ ở trường, những người thậm chí chưa từng thấy bất kỳ ngôn ngữ lập trình nào trước đây.

Nếu ai đó có kinh nghiệm với các ngôn ngữ khác và kinh nghiệm với Scala (và người mà tôi cho là đã làm việc với Scalaz ít nhất một tuần và có đồng nghiệp để giải thích những điều khó khăn hơn) vẫn còn nhầm lẫn; sau đó là bằng chứng rằng nó đã thêm phức tạp.


11
Điều này chỉ đơn giản là không đúng sự thật:"Well written code can be read by people who aren't familiar with the specific programming language."
Andres F.

@Andres: Đó là sự thật ... đến một điểm. Mã được viết tốt sẽ tách biệt logic nghiệp vụ khỏi các chi tiết triển khai và logic nghiệp vụ nên dễ đọc, bởi vì hầu hết những gì nó đang làm là thực hiện các cuộc gọi đơn giản đến các hàm trợ giúp có tên. Những người trợ giúp có thể sử dụng tất cả các loại tính năng ngôn ngữ, tất nhiên, và đòi hỏi kinh nghiệm nặng nề với ngôn ngữ và thư viện để hiểu.
Ben Voigt

4
Tôi tin rằng sau đây là APL thành ngữ : x[⍋x←6?40]. Bạn nghĩ nó làm gì? Tôi chắc chắn sẽ không biết đến
bdesham

3
@Brendan Chỉ trong cùng một mô hình (và thậm chí sau đó, đôi khi không). Ví dụ, Prolog, Java và APL khác nhau đến mức tôi sẽ lập luận rằng nếu bạn chỉ biết một trong những ngôn ngữ đó (và không có ngôn ngữ nào khác), bạn không thể đọc hai ngôn ngữ kia, bất kể bạn biết tiếng đầu tiên như thế nào. (Nghiêm túc, trong ví dụ của bdesham, làm thế nào ma quỷ bạn phải diễn giải "cây Giáng sinh" nếu bạn không biết bất kỳ APL nào?)
Izkata

1
Brendan, định nghĩa của bạn về văn bản tốt là không chuẩn. Được viết tốt luôn liên quan đến ngôn ngữ và cộng đồng của nó. Một chương trình bằng ngôn ngữ X được viết tốt nếu nó không có lỗi, nó hiệu quả và rõ ràng ... cho các đối tượng nhất định! Điều này áp dụng cho ngôn ngữ viết nói chung, nhân tiện: luôn biết đối tượng của bạn. Những gì phù hợp cho (nói) một bài báo khoa học có lẽ không phù hợp cho một email gửi cho mẹ của bạn.
Andres F.
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.