Chức năng đọc lập trình chức năng [đóng]


13

Tôi tò mò về điều này bởi vì tôi nhớ lại trước khi học bất kỳ ngôn ngữ chức năng nào, tôi nghĩ tất cả chúng đều khủng khiếp, khủng khiếp, khủng khiếp không thể đọc được. Bây giờ tôi biết Haskell và f #, tôi thấy mất ít thời gian hơn để đọc ít mã hơn, nhưng mã nhỏ đó làm được nhiều hơn một lượng tương đương trong một ngôn ngữ bắt buộc, vì vậy nó có cảm giác như một lợi ích ròng và tôi không cực kỳ Thực hành trong chức năng.

Đây là câu hỏi của tôi, tôi liên tục nghe từ những người OOP rằng phong cách chức năng là không thể đọc được. Tôi tò mò nếu đây là trường hợp và tôi đang tự lừa dối bản thân mình, hoặc nếu họ dành thời gian để học một ngôn ngữ chức năng, toàn bộ phong cách sẽ không còn khó đọc hơn OOP?

Có ai nhìn thấy bất kỳ bằng chứng hoặc có bất kỳ giai thoại nào mà họ thấy điều này đi bằng cách này hay cách khác với tần suất đủ để có thể nói? Nếu viết theo chức năng thực sự có khả năng đọc thấp hơn thì tôi không muốn tiếp tục sử dụng nó, nhưng tôi thực sự không biết liệu đó có phải là trường hợp hay không ..


1
Tôi nhớ đã xem mã cho "Super Nario Brothers" svn.coderepos.org/share/lang/haskell/nario khi tôi hầu như không biết gì về lập trình chức năng và nhớ suy nghĩ 'Wow. Điều này dường như thực sự có thể đọc được '
WuHoUnited



3
@BlackICE linq và lambdas khác xa với định nghĩa "lập trình chức năng". Lập trình hàm liên quan đến các hệ thống kiểu thường xuyên hơn không phải vì khi bạn bắt đầu nhận ra các hàm là kiểu chứ không chỉ là các đối tượng / lớp / bản ghi là kiểu, bạn sẽ có rất nhiều khả năng và kỹ thuật mới. Các biểu thức LINQ và Lambda (hoặc danh sách các hàm đơn vị và bậc cao hơn) chỉ là hai kỹ thuật kết quả cụ thể, trong đó có nhiều kỹ thuật khác.
Jimmy Hoffa

Câu trả lời:


15

Mã dễ đọc là rất chủ quan . Bởi vì điều này, những người khác nhau sẽ xem xét cùng một mã có thể đọc hoặc không thể đọc được.

Một bài tập, x = x + 1nghe có vẻ kỳ lạ đối với một nhà toán học, bởi vì một bài tập có vẻ sai lệch tương tự như so sánh.

Một mẫu thiết kế OOP đơn giản sẽ hoàn toàn không rõ ràng đối với người không quen thuộc với các mẫu này. Hãy xem xét đơn lẻ . Ai đó sẽ hỏi "Tại sao tôi cần một nhà xây dựng tư nhân? Phương pháp bí ẩn là getInstance() gì? Tại sao chúng ta không tạo một biến toàn cục và gán một đối tượng ở đó?"

Điều tương tự cũng áp dụng cho một mã FP. Trừ khi bạn biết các mẫu logic đằng sau hậu trường, sẽ rất khó để hiểu một cái gì đó rất cơ bản, ví dụ như làm thế nào để truyền một hàm làm đối số cho hàm khác.

Nói điều này, người ta nên hiểu rằng FP không phải là viên đạn bạc. Có nhiều ứng dụng mà FP sẽ khó áp dụng và do đó, nó sẽ dẫn đến một mã dễ đọc hơn .


Mọi người nên tạo ra một cái gì đó tương tự như chính họ (nhân loại). Ví dụ, ngay cả trong tầm nhìn máy tính, chúng ta có mạng lưới thần kinh. Cơ thể con người bao gồm các đối tượng, thuộc tính, phương thức và chúng tôi mô tả những thứ khác bằng cách sử dụng các đối tượng, thuộc tính, phương thức. Vì vậy, lập trình chức năng không có ý nghĩa gì
user25 30/12/18

12

Câu trả lời ngắn:

Một trong những yếu tố khiến mọi người nói rằng mã lập trình chức năng rất khó đọc là nó ưu tiên cho một cú pháp nhỏ gọn hơn.

Câu trả lời dài:

Bản thân chức năng lập trình không thể đọc được hoặc không đọc được, vì đó là một mô hình, không phải là một kiểu viết mã. Trong C # chẳng hạn, lập trình chức năng trông giống như:

return this.Data.Products
    .Where(c => c.IsEnabled)
    .GroupBy(c => c.Category)
    .Select(c => new PricesPerCategory(category: c.Key, minimum: c.Min(d => d.Price), maximum: c.Max(d => d.Price)));

và sẽ được xem là có thể đọc được bởi bất kỳ người nào có đủ kinh nghiệm về Java, C # hoặc các ngôn ngữ tương tự.

Mặt khác, cú pháp ngôn ngữ nhỏ gọn hơn đối với nhiều ngôn ngữ chức năng (bao gồm Haskell và F #) so với các ngôn ngữ OOP phổ biến, ưu tiên cho các ký hiệu hơn là từ tiếng Anh.

Điều này cũng áp dụng cho các ngôn ngữ bên ngoài FP. Nếu bạn so sánh các ngôn ngữ OOP phổ biến với một số ngôn ngữ ít phổ biến hơn có xu hướng sử dụng nhiều từ tiếng Anh hơn, những ngôn ngữ cuối cùng sẽ cảm thấy dễ hiểu hơn đối với những người không có kinh nghiệm lập trình.

Đối chiếu:

public void IsWithinRanges<T>(T number, param Range<T>[] ranges) where T : INumeric
{
    foreach (var range in ranges)
    {
        if (number >= range.Left && number <= range.Right)
        {
            return true;
        }
    }

    return false;
}

đến:

public function void IsWithinRanges
    with parameters T number, param array of (Range of T) ranges
    using generic type T
    given that T implements INumeric
{
    for each (var range in ranges)
    {
        if (number is from range.Left to range.Right)
        {
            return true;
        }
    }

    return false;
}

Theo cùng một cách:

var a = ((b - c) in 1..n) ? d : 0;

có thể được diễn đạt bằng một ngôn ngữ tưởng tượng như:

define variable a being equal to d if (b minus c) is between 1 and n or 0 otherwise;

Khi cú pháp ngắn hơn là tốt hơn?

Mặc dù cú pháp dài hơn dễ hiểu hơn đối với người mới bắt đầu, cú pháp gọn hơn sẽ dễ dàng hơn cho các nhà phát triển có kinh nghiệm. Mã ngắn hơn có nghĩa là ít ký tự để nhập, có nghĩa là năng suất cao hơn.

Đặc biệt, nó thực sự không có ý nghĩa khi buộc một người gõ từ khóa để chỉ ra một cái gì đó có thể được suy ra từ cú pháp.

Ví dụ:

  • Trong PHP bạn cần gõ functiontrước mỗi hàm hoặc phương thức, không có lý do cụ thể để làm điều đó.

  • Ada luôn làm tôi kinh hoàng khi buộc các nhà phát triển phải gõ rất nhiều từ tiếng Anh, đặc biệt là vì không có IDE chính xác với tính năng tự động hoàn thành. Gần đây tôi đã không sử dụng Ada và hướng dẫn chính thức của họ không hoạt động nên tôi không thể đưa ra một ví dụ; nếu bất cứ ai có một ví dụ, vui lòng sửa đổi câu trả lời của tôi.

  • Cú pháp 1..n, sử dụng trong nhiều FP (và Matlab), có thể được thay thế bằng between 1, nhoặc between 1 and nhoặc between (1, n). Các betweentừ khóa làm cho nó dễ dàng hơn để hiểu đối với những người không quen thuộc với cú pháp ngôn ngữ, nhưng vẫn còn, hai chấm là nhanh hơn nhiều để gõ.


8
Tôi đồng ý với tình cảm, nhưng vì những lý do khác nhau. Đây không phải là về việc một chuyên gia có thể viết mã dễ dàng như thế nào , vì mã thường được đọc thường xuyên hơn nhiều so với viết. Mã ngắn hơn cũng có thể giúp dễ đọc, bằng cách không lãng phí thời gian quý báu, không gian màn hình và khả năng tinh thần nếu có gì đó rõ ràng từ một chỉ báo ngắn hơn (ví dụ, dòng mới thay vì dấu chấm phẩy, dù sao hai sự trùng hợp này). Nó cũng có thể bị tổn thương khi nó trở nên quá khó hiểu (ví dụ, tôi thích for x in xshơn for x xs, vì nó giúp tôi phân biệt biến vòng lặp và vùng chứa).

Nhiều người tôi thấy phàn nàn về FP cũng phàn nàn về đoạn trích C # mà bạn đã liệt kê như bạn đã nói, đó cũng là một ví dụ về FP. Có lẽ đây là vấn đề của các đồng nghiệp của tôi hơn là khả năng đọc nếu hầu hết những người OOP thấy đoạn trích đó có thể đọc được, mặc dù tôi không hoàn toàn thuyết phục hầu hết những người OOP làm từ kinh nghiệm của tôi .. vì vậy tôi cảm thấy không chắc chắn về chủ đề này.
Jimmy Hoffa

@Jimmy Hoffa: Xem lập trình viên.stackexchange.com/a/158721/6605 nơi tôi thảo luận chính xác đoạn trích C # và cách các lập trình viên mới bắt đầu cảm nhận.
Arseni Mourzenko

1
@Sergiy: trong Java hoặc C #, chữ ký phương thức không có methodtừ khóa trong đó. Ví dụ : public int ComputePrice(Product product). Thêm từ khóa như vậy, như những gì PHP đã làm, chỉ thêm lộn xộn thay vì làm cho mọi thứ dễ đọc hơn. Nếu một lập trình viên không thể hiểu rằng một hàm là một hàm từ chữ ký của nó, thì lập trình viên này không có kinh nghiệm gì, hoặc mã này khó đọc hơn nhiều so với mã xấu nhất tôi từng thấy.
Arseni Mourzenko

1
@Sergiy: có những trường hợp mà tính dài dòng có thể giúp ích (nếu không, chúng ta sẽ thấy các ngôn ngữ và mã như p i ComputePrice(product): _.unitPrice * ~.cart[_]), nhưng một số ngôn ngữ đẩy nó đi quá xa. Ví dụ về functiontừ khóa dư thừa trong PHP là một ví dụ tốt.
Arseni Mourzenko

6

Tôi nghĩ một trong những lý do là lập trình chức năng có xu hướng hoạt động với các khái niệm trừu tượng hơn nhiều. Điều này làm cho mã ngắn hơn và dễ đọc hơn đối với những người biết và hiểu các khái niệm (vì chúng thể hiện một cách khéo léo bản chất của vấn đề), nhưng không thể đọc được đối với những người không quen thuộc với chúng.

Ví dụ, đối với một lập trình viên chức năng, việc viết một mã có thể thất bại tại các điểm khác nhau trong Maybeđơn nguyên hoặc Eitherđơn nguyên là điều tự nhiên . Hoặc, để viết một tính toán có trạng thái với sự giúp đỡ của Stateđơn nguyên. Nhưng đối với một người không hiểu khái niệm về các đơn nguyên, tất cả điều này có vẻ giống như một loại phép thuật đen.

Vì vậy, tôi nghĩ sẽ hợp lý khi sử dụng các bit lập trình chức năng ngay cả trong một nhóm người OOP, miễn là người ta sử dụng các khái niệm dễ hiểu hoặc học hỏi, như ánh xạ lên một bộ sưu tập có chức năng hoặc đóng .

(Và tất nhiên, nó cũng phụ thuộc vào lập trình viên đã viết một số đoạn mã. Bạn có thể viết mã không thể đọc được khủng khiếp bằng bất kỳ ngôn ngữ nào, cũng như bạn có thể viết theo phong cách đẹp và sạch sẽ.)


2

Khả năng đọc không có gì để làm với các mô hình, mô hình và như vậy. Càng nhiều mã phản ánh ngữ nghĩa của miền vấn đề của bạn, nó càng vận hành một thuật ngữ và thành ngữ của miền vấn đề như vậy, nó càng dễ đọc hơn.

Đây là lý do tại sao mã OOP hoàn toàn không thể đọc được: không phải là nhiều vấn đề trong thế giới thực được thể hiện một cách tự nhiên theo các phân loại phân cấp. Các đối tượng truyền tin nhắn cho nhau là một khái niệm kỳ lạ, và nó rất xa với bất cứ thứ gì "thực". Đáng ngạc nhiên, có nhiều khái niệm thế giới thực hơn nhiều có thể được ánh xạ tự nhiên đến các thành ngữ chức năng. Các vấn đề có xu hướng được xác định khai báo, do đó một giải pháp khai báo là tự nhiên hơn.

Mặc dù, có nhiều ngữ nghĩa khác có thể gần với thế giới thực hơn là một OOP thuần túy, thuần túy, dataflow thuần túy hoặc bất cứ thứ gì có thể. Và do thực tế này, một cách tiếp cận định hướng ngôn ngữ để giải quyết vấn đề tạo ra mã dễ đọc nhất, đánh bại tất cả các mô hình "thuần túy" hiện có. Với các ngôn ngữ dành riêng cho tên miền, mọi vấn đề đều được thể hiện bằng thuật ngữ tự nhiên của riêng nó. Và các ngôn ngữ chức năng tốt hơn một chút so với công cụ chính của OOP trong việc hỗ trợ triển khai DSL (mặc dù, có sẵn các cách tiếp cận tốt hơn nhiều).


1

Mã dễ đọc là chủ quan. Tôi chắc chắn rằng một số người chỉ trích nó thông qua sự thiếu hiểu biết. Có những thành ngữ tự nhiên khác nhau trong cách thực hiện các mô hình phổ biến. Ví dụ: mẫu Khách truy cập không thực sự có ý nghĩa trong một ngôn ngữ có khớp mẫu .

Kiểu suy luận có thể là một tính năng khó khăn. Thông thường, đó là một công cụ thúc đẩy phát triển tuyệt vời, tuy nhiên, đôi khi có thể khó tìm ra loại nào có liên quan do thiếu bối cảnh dẫn đến các lỗi khó hiểu. Điều này không giới hạn ở những ngôn ngữ lập trình chức năng - tôi cũng đã thấy nó trong các mẫu C ++!

Ngôn ngữ hiện đại có xu hướng đa mô hình . Điều này bao gồm cả C # và F #. Có thể viết một kiểu chức năng trong C # và một kiểu bắt buộc trong F #. Những người chỉ trích các ngôn ngữ Chức năng có thể viết mã chức năng bằng ngôn ngữ hướng đối tượng của họ.

Phát triển thương mại trong các ngôn ngữ chức năng vẫn còn tương đối chưa trưởng thành. Tôi đã thấy một số sai lầm được coi là hình thức xấu trong bất kỳ ngôn ngữ nào. Nhu la:

  1. Thay đổi phong cách khi bạn học ngôn ngữ (và không tái cấu trúc) dẫn đến sự không nhất quán.
  2. Quá nhiều trong một tập tin.
  3. Quá nhiều tuyên bố trên một dòng.

Liên quan đến các lỗi tôi cũng sẽ thêm: 4. Sử dụng quá mức các ký hiệu, ví dụ: ~ @ # $% ^ & * () -_ + = \ | /.,; 5. Các tính năng tiềm ẩn: khai báo tùy chọn / từ khóa / tuyên bố, chuyển đổi ngầm, v.v.;
Sergiy Sokolenko
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.