2012-02-29 29 views
5

tôi đã nhận thấy rằng có những khái niệm cốt lõi chắc chắn rằng rất nhiều tín đồ lập trình chức năng bám vào:Tại sao lập trình hàm tốt?

  • Tránh tình trạng

  • Tránh dữ liệu có thể thay đổi

  • Giảm thiểu tác dụng phụ

  • etc ...

Tôi không chỉ tự hỏi điều gì khác làm cho lập trình chức năng, nhưng tại sao những ý tưởng cốt lõi này lại tốt? Tại sao nó tốt để tránh nhà nước, và phần còn lại?

Trả lời

11

Câu trả lời đơn giản là nếu bạn không có thêm trạng thái cần lo lắng, mã của bạn sẽ đơn giản hơn để giải thích. Mã đơn giản dễ bảo trì hơn. Bạn không cần phải lo lắng về những thứ bên ngoài một đoạn mã cụ thể (như một hàm) để sửa đổi nó. Điều này có phân nhánh thực sự hữu ích cho những thứ như thử nghiệm. Nếu mã của bạn không phụ thuộc vào một số trạng thái, việc tạo các kiểm tra tự động cho mã đó trở nên dễ dàng hơn nhiều, vì bạn không cần phải lo lắng về việc khởi tạo một số trạng thái.

Có mã không quốc tịch giúp bạn dễ dàng tạo các chương trình luồng hơn vì bạn không cần phải lo lắng về hai luồng thực hiện sửa đổi/đọc một mẩu dữ liệu được chia sẻ cùng một lúc. Chủ đề của bạn có thể chạy mã độc lập và điều này có thể tiết kiệm rất nhiều thời gian phát triển.

Về cơ bản, tránh trạng thái tạo các chương trình đơn giản hơn. Theo cách nào đó, có ít "bộ phận chuyển động" (tức là, các dòng mã có thể tương tác), vì vậy điều này thường có nghĩa là mã này đáng tin cậy hơn và chứa ít lỗi hơn. Về cơ bản, mã càng đơn giản thì càng ít sai. Với tôi đây là bản chất của việc viết mã tiểu bang.

Có rất nhiều lý do khác để tạo mã không có trạng thái, "chức năng", nhưng tất cả chúng đều hết sức đơn giản đối với tôi.

+1

Có lẽ nên đề cập đến việc đồng thời dễ dàng hơn để làm chính xác? – ebaxt

+0

Có, Đã thêm. Cảm ơn. :) – Oleksi

+0

+1. Vâng, Oleksi. –

5

Ngoài những gì @Oleksi cho biết, còn có một điều quan trọng khác: minh bạch tham chiếu và cấu trúc dữ liệu giao dịch. Tất nhiên, bạn không cần một ngôn ngữ lập trình chức năng để làm như vậy, nhưng nó dễ dàng hơn một chút với chúng.

Purely functional data structures được đảm bảo giữ nguyên - nếu một hàm trả về một cây, nó sẽ luôn là cùng một cây và tất cả các biến đổi tiếp theo sẽ tạo bản sao mới của nó. Sẽ dễ dàng hơn khi quay lại bất kỳ phiên bản trước nào của cấu trúc dữ liệu theo cách này, điều này quan trọng đối với nhiều thuật toán cần thiết.

5

Rất thường, lập trình chức năng có nghĩa là:

  • khuyến khích việc sử dụng (hạng nhất) chức năng
  • ngăn cản việc sử dụng (có thể thay đổi) nhà nước

Tại sao đột biến một vấn đề? Hãy suy nghĩ về nó: đột biến là cấu trúc dữ liệu những gì goto là để kiểm soát dòng chảy. Tức là, nó cho phép bạn tùy ý "nhảy" vào một thứ hoàn toàn khác theo một cách khá phi cấu trúc. Do đó, nó đôi khi hữu ích, nhưng hầu hết thời gian khá có hại cho khả năng đọc, khả năng kiểm tra và tính sáng tác.

+1

+1 để so sánh trạng thái có thể thay đổi với goto! – Ingo

2

Một tính năng chức năng điển hình là "không phân loại".Trong khi có vẻ hơi kỳ quặc khi gọi đây là một tính năng, đó là, vì hai lý do (liên quan một cách nào đó):

  • Các mối quan hệ phụ sẽ dẫn đến một loạt các vấn đề không rõ ràng. Nếu bạn không giới hạn bản thân để thừa kế đơn hoặc kết hợp, bạn kết thúc với vấn đề kim cương. Quan trọng hơn là bạn phải đối phó với phương sai (hiệp phương sai, contravariance, bất biến), mà nhanh chóng trở thành một cơn ác mộng, đặc biệt là đối với các thông số kiểu (generics a.k.a.). Có nhiều lý do khác, và ngay cả trong các ngôn ngữ OO, bạn nghe các câu lệnh như "thích thành phần hơn thừa kế". Mặt khác, nếu bạn chỉ đơn giản là loại bỏ phân loại, bạn có thể giải thích nhiều hơn về hệ thống kiểu của bạn, dẫn đến khả năng có suy luận kiểu gần như thường được thực hiện bằng cách sử dụng phần mở rộng của suy luận kiểu Hindley Milner. Quay lại đầu trang

Tất nhiên đôi khi bạn sẽ bỏ lỡ phân loại, nhưng các ngôn ngữ như Haskell đã tìm thấy câu trả lời hay cho vấn đề đó: Nhập các lớp, cho phép xác định loại "giao diện chung" (hoặc "bộ hoạt động chung")) cho một số loại không liên quan khác. Sự khác biệt đối với các ngôn ngữ OO là các lớp kiểu có thể được định nghĩa "sau đó", mà không cần chạm vào các định nghĩa kiểu gốc. Nó chỉ ra rằng bạn có thể làm hầu như tất cả mọi thứ với các lớp loại mà bạn có thể làm với subtyping, nhưng trong một cách linh hoạt hơn nhiều (và không ngăn chặn suy luận kiểu). Đó là lý do tại sao các ngôn ngữ khác bắt đầu sử dụng các mechnisms tương tự (ví dụ: chuyển đổi ngầm trong Scala hoặc các phương thức mở rộng trong C# và Java 8)

Các vấn đề liên quan