Là một lượng nhỏ lập trình chức năng có thể hiểu được bởi những người không phải là FP? [đóng cửa]


43

Trường hợp : Tôi đang làm việc tại một công ty, đang viết một ứng dụng bằng Python đang xử lý rất nhiều dữ liệu trong mảng. Tôi là nhà phát triển duy nhất của chương trình này vào lúc này, nhưng có lẽ nó sẽ được sử dụng / sửa đổi / gia hạn trong tương lai (1-3 năm) bởi một số lập trình viên khác, tại thời điểm này tôi không biết. Tôi có thể sẽ không trực tiếp giúp đỡ sau đó, nhưng có thể cung cấp một số hỗ trợ qua email nếu tôi có thời gian cho nó.

Vì vậy, là một nhà phát triển đã học lập trình chức năng (Haskell), tôi có xu hướng giải quyết, ví dụ, lọc như thế này:

filtered = filter(lambda item: included(item.time, dur), measures)

Phần còn lại của mã là OO, đó chỉ là một số trường hợp nhỏ mà tôi muốn giải quyết nó như thế này, bởi vì nó đơn giản hơn và đẹp hơn theo tôi.

Câu hỏi : Hôm nay có ổn không khi viết mã như thế này?

  • Làm thế nào để một nhà phát triển chưa viết / học FP phản ứng với mã như thế này?
  • Có đọc được không?
  • Có thể sửa đổi?
  • Tôi có nên viết tài liệu như giải thích cho trẻ những gì dòng này không?

     # Filter out the items from measures for which included(item.time, dur) != True

Tôi đã hỏi ông chủ của mình và anh ta chỉ nói "FP là ma thuật đen, nhưng nếu nó hoạt động và là giải pháp hiệu quả nhất, thì sử dụng nó là được."

Ý kiến ​​của bạn như thế nào? Là một lập trình viên không phải là FP, bạn phản ứng với mã như thế nào? Là mã "googable" để bạn có thể hiểu những gì nó làm? Tôi rất thích phản hồi về điều này.


14
Theo tôi, nhiều ngôn ngữ hiện đại cho phép một số mức độ lập trình chức năng và sử dụng nó ngày càng trở nên phổ biến. Cá nhân tôi muốn nói hãy thực hiện nó (ít nhất là cho các tác vụ lọc / ánh xạ tương đối đơn giản).
Joachim Sauer

Tôi không thể cho bạn một câu trả lời không bị ảnh hưởng, vì tôi thích FP. Nó sẽ là một ý tưởng tốt để thêm một bình luận, nếu nó vượt quá đơn giản.
Bruno Schäpper

3
Nhận xét của bạn có thể rõ ràng hơn; bộ lọc bao gồm các yếu tố mà bài kiểm tra là Đúng, vì vậy bình luận của bạn có thể đọc # Select the item's from measures for which included(item.time, dur) == True:, tránh tiêu cực kép luôn cải thiện sự hiểu biết.
Martijn Pieters

6
Bạn đã xem xét sử dụng danh sách hiểu thay thế? Chúng thường được coi là "pythonic" nhiều hơn so với bản đồ / bộ lọc.
phant0m

2
@MatjazMuhic Chà, thật đẹp ...;)
kd35a

Câu trả lời:


50

Có đọc được không?

Đối với tôi: Có, nhưng tôi đã hiểu, rằng cộng đồng Python thường dường như coi việc hiểu danh sách là một giải pháp sạch hơn là sử dụng map()/ filter().

Trên thực tế, GvR thậm chí đã cân nhắc bỏ hoàn toàn các chức năng đó.

Xem xét điều này:

filtered = [item for item in measures if included(item.time, dur)]

Hơn nữa, điều này có lợi ích là việc hiểu danh sách sẽ luôn trả về một danh sách. map()filter()mặt khác sẽ trả về một trình vòng lặp trong Python 3.

Lưu ý: Nếu bạn muốn có một trình vòng lặp thay thế, thì đơn giản như thay thế []bằng ():

filtered = (item for item in measures if included(item.time, dur))

Thành thật mà nói, tôi thấy ít hoặc không có lý do để sử dụng map()hoặc filter()trong Python.

Có thể sửa đổi?

Vâng, chắc chắn, tuy nhiên, có một điều để làm cho điều đó dễ dàng hơn: Làm cho nó trở thành một chức năng, không phải là lambda.

def is_included(item):
    return included(item.time, dur)
filtered = filter(is_included, measures)
filtered = [item for item in measures if is_included(item)]

Nếu tình trạng của bạn trở nên phức tạp hơn, điều này sẽ mở rộng quy mô dễ dàng hơn, đồng thời, nó cho phép bạn sử dụng lại séc của mình. (Lưu ý rằng bạn có thể tạo các chức năng bên trong các chức năng khác, điều này có thể giữ nó gần hơn với nơi nó được sử dụng.)

Làm thế nào để một nhà phát triển chưa viết / học FP phản ứng với mã như thế này?

Anh ta tìm kiếm tài liệu Python và biết cách nó hoạt động năm phút sau. Mặt khác, anh ta không nên lập trình bằng Python.

map()filter()cực kỳ đơn giản. Nó không giống như bạn yêu cầu họ hiểu các đơn nguyên. Đó là lý do tại sao tôi không nghĩ bạn cần viết những bình luận như vậy. Sử dụng tên biến và hàm tốt, sau đó mã gần như tự giải thích. Bạn không thể lường trước những tính năng ngôn ngữ mà nhà phát triển không biết. Đối với tất cả những gì bạn biết, nhà phát triển tiếp theo có thể không biết từ điển là gì.

Những gì chúng ta không hiểu thường không thể đọc được cho chúng ta. Do đó, bạn có thể lập luận rằng nó không kém phần dễ đọc hơn so với việc hiểu danh sách nếu bạn chưa từng thấy một trong số họ trước đây. Nhưng như Joshua đã đề cập trong bình luận của mình, tôi cũng tin rằng điều quan trọng là phải phù hợp với những gì các nhà phát triển khác sử dụng - ít nhất là nếu sự thay thế không mang lại lợi thế đáng kể.


5
Cũng có thể đề cập đến các biểu thức của trình tạo , hoạt động tương tự như hiểu danh sách nhưng trả về các trình tạo thay vì danh sách, như mapfilterthực hiện trong python 3.
James

@James: Ý tưởng tuyệt vời, tôi đã thêm chúng vào bài viết của mình. Cảm ơn!
phant0m

2
Tôi thường đưa ra reducemột ví dụ ngược lại để bạn luôn có thể sử dụng một đối số hiểu danh sách , vì nó tương đối khó thay thế reducebằng một trình tạo nội tuyến hoặc hiểu danh sách.
kojiro

4
+1 để lưu ý thành ngữ ưa thích của ngôn ngữ được đề cập. Tính nhất quán của IMHO có giá trị to lớn và sử dụng một ngôn ngữ theo cách mà một phần đáng kể của "người nói" có thể cung cấp khả năng duy trì nhiều hơn thậm chí là nhận xét đôi khi.
Joshua Drake

4
+1 cho "Anh ấy googles cho tài liệu Python và biết cách nó hoạt động năm phút sau. Nếu không, anh ấy không nên lập trình bằng Python."
Bjarke Freund-Hansen

25

Vì cộng đồng nhà phát triển đang lấy lại hứng thú với lập trình chức năng, không có gì lạ khi thấy một số lập trình chức năng trong các ngôn ngữ ban đầu hướng đối tượng hoàn toàn. Một ví dụ điển hình là C #, trong đó các loại ẩn danh và biểu thức lambda cho phép ngắn hơn và biểu cảm thông qua lập trình chức năng.

Điều này đang được nói, lập trình chức năng là lạ cho người mới bắt đầu. Ví dụ, khi trong một khóa đào tạo, tôi đã giải thích cho người mới bắt đầu cách họ có thể tăng cường mã thông qua lập trình chức năng trong C #, một số trong số họ không bị thuyết phục và một số người nói rằng mã gốc dễ hiểu hơn đối với họ. Ví dụ tôi đưa ra cho họ là như sau:

Mã trước khi tái cấu trúc:

var categorizedProducts = new Dictionary<string, List<Product>>();

// Get only enabled products, filtering the disabled ones, and group them by categories.
foreach (var product in this.Data.Products)
{
    if (product.IsEnabled)
    {
        if (!categorizedProducts.ContainsKey(product.Category))
        {
            // The category is missing. Create one.
            categorizedProducts.Add(product.Category, new List<Product>());
        }

        categorizedProducts[product.Category].Add(product);
    }
}

// Walk through the categories.
foreach (var productsInCategory in categorizedProducts)
{
    var minimumPrice = double.MaxValue;
    var maximumPrice = double.MinValue;

    // Walk through the products in a category to search for the maximum and minimum prices.
    foreach (var product in productsInCategory.Value)
    {
        if (product.Price < minimumPrice)
        {
            minimumPrice = product.Price;
        }

        if (product.Price > maximumPrice)
        {
            maximumPrice = product.Price;
        }
    }

    yield return new PricesPerCategory(category: productsInCategory.Key, minimum: minimumPrice, maximum: maximumPrice);
}

Cùng mã sau khi tái cấu trúc bằng cách sử dụng FP:

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

Điều này khiến tôi nghĩ rằng:

  • bạn không nên lo lắng nếu bạn biết rằng nhà phát triển tiếp theo sẽ duy trì mã của bạn sẽ có đủ kinh nghiệm tổng thể và một số kiến ​​thức về lập trình chức năng, nhưng:

  • mặt khác, hoặc tránh lập trình chức năng, hoặc đưa ra một nhận xét dài dòng giải thích đồng thời cú pháp, ưu điểm và khả năng của cách tiếp cận của bạn so với lập trình phi chức năng.


8
+1 nếu FP không làm cho mã của bạn dễ đọc hơn đối với bất kỳ ai , bạn đang làm sai.
Gyorgy Andottok

7
Tôi có thể thấy cách cô lập một người không bao giờ nhìn thấy FP trước đây có thể xem xét đoạn trích trước dễ đọc hơn đoạn sau. Nhưng nếu chúng ta nhân số này với 100 thì sao? Đọc 100 câu ngắn gọn gần giống như tiếng Anh mô tả những gì so với hàng ngàn dòng ống nước như thế nào mã. Khối lượng mã tuyệt đối, dù quen thuộc đến đâu, nên quá lớn đến nỗi sự quen thuộc không còn là một chiến thắng lớn như vậy nữa. Tại một số điểm, mọi người trước tiên phải dễ dàng hơn với các yếu tố của FP và sau đó đọc một số dòng so với đọc hàng ngàn dòng mã quen thuộc.
Esailija

7
Điều làm tôi băn khoăn nhất là chúng tôi hài lòng khi tin rằng các nhà phát triển không chấp nhận phong cách chức năng. Những lợi thế đã được chứng minh nhiều lần, mô hình được hỗ trợ bởi các ngôn ngữ chính. Nếu mọi người thiếu khả năng hiểu các kỹ thuật chức năng, họ nên được dạy hoặc nên tự dạy mình, ngay cả khi họ không có ý định sử dụng nó. Tôi ghét XSLT với niềm đam mê cháy bỏng, nhưng điều đó không ngăn tôi học nó, như một chuyên gia.
Sprague

2
@MainMa Quan điểm của bạn là hoàn toàn hợp lệ, đáng lẽ tôi phải cụ thể hơn. Ý tôi là một nhà phát triển trong bất kỳ ngôn ngữ nào được mong đợi sẽ sử dụng các tính năng của các ngôn ngữ đó một cách hiệu quả. Ví dụ: sử dụng 'kiểu chức năng' trong C # (sử dụng bộ lọc / ánh xạ / giảm lập trình kiểu, hoặc các hàm truyền / trả lại) không có gì mới, và vì vậy tôi nghĩ rằng bất kỳ nhà phát triển C # nào không có khả năng đọc các câu lệnh đó đều nên cập nhật kỹ năng ... có lẽ rất nhanh. Tôi chắc chắn nghĩ rằng mọi nhà phát triển nên học một chút Haskell, nhưng chỉ vì lý do học thuật. Đây là một điều khác biệt.
Sprague

2
@Sprague: Tôi nhận được quan điểm của bạn và đồng ý với nó. Chỉ là chúng ta khó có thể mong đợi các lập trình viên C # bắt đầu sử dụng mô hình từ FP, khi có quá nhiều lập trình viên thậm chí không sử dụng thuốc generic. Cho đến khi có rất nhiều lập trình viên không có kỹ năng, thanh công việc của chúng tôi sẽ thấp, đặc biệt là vì hầu hết những người không có nền tảng kỹ thuật không hiểu gì về sự phát triển.
Arseni Mourzenko

20

Tôi là một lập trình viên không phải là FP và gần đây tôi đã sửa đổi mã của đồng nghiệp của mình bằng JavaScript. Có một yêu cầu http với một cuộc gọi lại trông rất giống với tuyên bố được bao gồm bởi bạn. Tôi phải nói rằng tôi đã mất một thời gian (như nửa giờ) để tìm ra tất cả (mã tất cả không quá lớn).

Không có bình luận, và tôi nghĩ rằng không cần thiết cho bất kỳ. Tôi thậm chí không yêu cầu đồng nghiệp của mình giúp tôi hiểu mã của anh ấy.

Tính đến việc tôi đang làm việc khoảng 1,5 năm, tôi nghĩ rằng hầu hết các lập trình viên sẽ có thể hiểu và sửa đổi mã như vậy, kể từ khi tôi làm.

Bên cạnh đó, như Joachim Sauer đã nói trong bình luận của mình, thường có những phần của FP bằng nhiều ngôn ngữ, như C # (ví dụ như indexOf). Vì vậy, nhiều lập trình viên không phải là người giải quyết vấn đề này khá thường xuyên và đoạn mã bạn đưa vào không phải là điều gì đó đáng sợ hoặc không thể hiểu được.


1
Cám ơn bạn đã góp ý! Nó đã cho tôi thêm thông tin về quan điểm khác. Thật dễ dàng để bị mù tại nhà, và sau đó bạn không biết nó trông như thế nào khi bạn không biết FP :)
kd35a

1
@ kd35a, bạn được chào đón. May mắn thay, tôi có thể khách quan ở đây))
superM

1
+1 để chỉ ra rằng nhiều ngôn ngữ hiện có chứa các yếu tố của FP.
Joshua Drake

LINQ là ví dụ chính về FP trong C #
Konrad Morawski

3

Tôi chắc chắn sẽ nói có!

Có nhiều khía cạnh của lập trình chức năng và sử dụng các hàm bậc cao hơn, như trong ví dụ của bạn, chỉ là một trong số đó.

Ví dụ: tôi coi việc viết các hàm thuần túy là cực kỳ quan trọng đối với bất kỳ phần mềm nào được viết bằng bất kỳ ngôn ngữ nào (trong đó theo "thuần túy" tôi có nghĩa là không có tác dụng phụ), bởi vì:

  • chúng dễ dàng hơn để kiểm tra đơn vị
  • chúng có khả năng tổng hợp cao hơn nhiều so với các chức năng phụ
  • chúng dễ gỡ lỗi hơn

Tôi cũng thường tránh biến đổi các giá trị và biến - một khái niệm khác mượn từ FP.

Cả hai kỹ thuật này đều hoạt động tốt trong Python và các ngôn ngữ khác thường không được phân loại là chức năng. Chúng thậm chí thường được hỗ trợ bởi chính ngôn ngữ (tức là finalcác biến trong Java). Do đó, các lập trình viên bảo trì trong tương lai sẽ không gặp phải rào cản lớn để hiểu mã.


2

Chúng tôi đã có cuộc thảo luận tương tự về một công ty tôi làm việc năm ngoái.

Các cuộc thảo luận liên quan đến "mã ma thuật" và liệu nó có được khuyến khích hay không. Khi nhìn vào nó nhiều hơn một chút, dường như mọi người có quan điểm rất khác nhau về cái thực sự là "mật mã ma thuật". Những người đưa ra cuộc thảo luận dường như chủ yếu có nghĩa là các biểu thức (trong PHP) sử dụng kiểu chức năng là "mã ma thuật" trong khi các nhà phát triển có nguồn gốc từ các ngôn ngữ khác sử dụng nhiều kiểu FP hơn trong mã của họ dường như nghĩ rằng mã ma thuật là đúng hơn khi bạn thực hiện bao gồm các tệp động thông qua tên tệp, v.v.

Chúng tôi chưa bao giờ đi đến bất kỳ kết luận tốt nào về điều này, hơn cả mọi người chủ yếu nghĩ rằng mã trông không quen thuộc là "ma thuật" hoặc khó đọc. Vì vậy, nó có phải là một ý tưởng tốt để tránh mã có vẻ xa lạ với người dùng khác? Tôi nghĩ rằng nó phụ thuộc vào nơi nó được sử dụng. Tôi sẽ không sử dụng các biểu thức kiểu fp (bao gồm tệp động và vv) trong một phương thức chính (hoặc các phần trung tâm quan trọng của ứng dụng) trong đó dữ liệu phải được tạo đường hầm theo cách rõ ràng và dễ đọc, trực quan. Mặt khác, tôi không nghĩ người ta nên ngại đẩy phong bì, các nhà phát triển khác có thể sẽ học hỏi nhanh chóng nếu họ phải đối mặt với mã FP và có thể có một số tài nguyên nội bộ tốt để tư vấn về các vấn đề.

TL; DR: Tránh ở phần trung tâm cấp cao của ứng dụng (cần đọc để biết tổng quan về chức năng của ứng dụng). Nếu không thì sử dụng nó.


Điểm tốt trong việc tránh sử dụng nó trong mã cấp cao hơn!
kd35a

Tôi luôn nghĩ rằng thiếu tính hình thức và rất nhiều cơ hội, trong việc xác định các kỹ thuật lập trình trong các loại khối khác nhau (như phương pháp tĩnh, phương thức công cộng, nhà xây dựng, v.v.) Câu trả lời hay ... nó khiến tôi phải xem lại một số của những suy nghĩ đó.
Sprague

2

Cộng đồng C ++ gần đây cũng có lambda và tôi tin rằng họ có cùng một câu hỏi. Câu trả lời có thể không giống nhau, mặc dù. Tương đương C ++ sẽ là:

std::copy_if(measures.begin(), measures.end(), inserter(filter),
  [dur](Item i) { return included(i, dur) } );

Bây giờ std::copykhông phải là mới và các _ifbiến thể cũng không mới, nhưng lambda thì có. Tuy nhiên, nó được xác định khá rõ ràng trong ngữ cảnh: durđược ghi lại và do đó không đổi, Item ithay đổi trong vòng lặp và returncâu lệnh duy nhất thực hiện tất cả công việc.

Điều này có vẻ chấp nhận được đối với nhiều nhà phát triển C ++. Mặc dù vậy, tôi chưa lấy mẫu ý kiến ​​về lambda cấp cao hơn, và tôi sẽ mong đợi sự chấp nhận ít hơn nhiều.


Điểm thú vị là có thể có các câu trả lời khác nhau tùy thuộc vào ngôn ngữ của nó. Có lẽ liên quan đến bài đăng @Christopher Käck về cách các lập trình viên PHP gặp nhiều vấn đề với loại công cụ này hơn các trình mã hóa Python.
kd35a

0

Đăng một đoạn mã cho một nhà phát triển đồng nghiệp không thông thạo python và hỏi anh ta nếu anh ta có thể dành 5 phút để kiểm tra mã để xem anh ta / cô ta có hiểu nó không.

Nếu có, bạn có thể là tốt để đi. Nếu không, bạn nên nhìn vào làm cho nó rõ ràng hơn.

Có thể đồng nghiệp của bạn là daft và không hiểu một cái gì đó là rõ ràng? Có, nhưng bạn phải luôn lập trình theo KISS.

Có lẽ mã của bạn hiệu quả hơn / ưa nhìn / thanh lịch hơn là một cách tiếp cận đơn giản hơn, bằng chứng ngu ngốc? Sau đó, bạn cần phải tự hỏi: tôi có cần phải làm điều này? Một lần nữa, nếu câu trả lời là không, thì đừng làm điều đó!

Nếu sau tất cả những điều này, bạn vẫn nghĩ rằng bạn cần và muốn thực hiện theo cách của FP, thì bằng mọi cách hãy làm điều đó. Hãy tin vào bản năng của bạn, chúng phù hợp với nhu cầu của bạn hơn hầu hết mọi người trên bất kỳ diễn đàn nào :)


vui lòng giải thích lý do cho downvote
Arnab Datta
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.