Những lợi ích của tính minh bạch tham chiếu cho một lập trình viên là gì?


18

Trong lập trình, những lợi ích của tính minh bạch tham chiếu là gì?

RT tạo ra một trong những khác biệt chính giữa các mô hình chức năng và mệnh lệnh, và thường được sử dụng bởi những người ủng hộ mô hình chức năng như một lợi thế rõ ràng so với mô hình mệnh lệnh; nhưng trong tất cả những nỗ lực của họ, những người ủng hộ này không bao giờ giải thích tại sao nó là một lợi ích cho tôi với tư cách là một lập trình viên .

Chắc chắn, họ sẽ có những giải thích học thuật về mức độ "thuần khiết" và "thanh lịch" của nó, nhưng làm thế nào để nó làm cho nó tốt hơn một mã "thuần túy" hơn? Làm thế nào nó có lợi cho tôi trong lập trình hàng ngày của tôi?

Lưu ý: Đây không phải là bản sao của tính minh bạch tham chiếu là gì? Câu hỏi sau đề cập đến chủ đề RT là , trong khi câu hỏi này nhấn mạnh lợi ích của nó (có thể không trực quan như vậy).




3
Transparword tham chiếu cho phép bạn sử dụng lý luận tương đương để: 1) Chứng minh các thuộc tính của mã và 2) viết chương trình. Có một vài cuốn sách về Haskell trong đó các tác giả nên làm thế nào bạn có thể bắt đầu từ một số phương trình mà bạn muốn một hàm thành fullfil và sử dụng lý do phương trình mà bạn kết thúc bằng cách thực hiện hàm đã nói, do đó, chắc chắn là đúng. Bây giờ mức độ này có thể được áp dụng trong lập trình "hàng ngày" có thể phụ thuộc vào bối cảnh ...
Bakuriu

2
@err Bạn có thích mã dễ dàng hơn để cấu trúc lại bởi vì bạn biết liệu gọi hàm hai lần có giống như lưu trữ giá trị của nó trong một biến không, sau đó sử dụng biến đã nói hai lần? Bạn có nói rằng đó là một lợi ích cho lập trình hàng ngày của bạn?
Andres F.

Lợi ích là bạn không cần lãng phí thời gian để suy nghĩ về tính không minh bạch giới thiệu. Kiểu như lợi ích của các biến là bạn không cần lãng phí thời gian suy nghĩ về phân bổ đăng ký.
dùng253751

Câu trả lời:


37

Lợi ích là các hàm thuần làm cho mã của bạn dễ dàng lý luận hơn. Hay nói cách khác, tác dụng phụ làm tăng độ phức tạp của mã của bạn.

Lấy một ví dụ về computeProductPricephương pháp.

Một phương thức thuần túy sẽ hỏi bạn về số lượng sản phẩm, một loại tiền tệ, v.v. Bạn biết rằng bất cứ khi nào phương thức được gọi với cùng một đối số, nó sẽ luôn tạo ra kết quả tương tự.

  • Bạn thậm chí có thể lưu trữ nó và sử dụng phiên bản lưu trữ.
  • Bạn có thể làm cho nó lười biếng và hoãn cuộc gọi của nó khi bạn thực sự cần nó, biết rằng giá trị sẽ không thay đổi trong khi đó.
  • Bạn có thể gọi phương thức nhiều lần, biết rằng nó sẽ không có tác dụng phụ.
  • Bạn có thể suy luận về chính phương thức này trong sự cô lập với thế giới, biết rằng tất cả những gì nó cần là các đối số.

Một phương thức không thuần túy sẽ phức tạp hơn để sử dụng và gỡ lỗi. Vì nó phụ thuộc vào trạng thái của các biến khác với các đối số và có thể thay đổi chúng, điều đó có nghĩa là nó có thể tạo ra các kết quả khác nhau khi được gọi nhiều lần hoặc không có cùng một hành vi khi không được gọi hoặc quá sớm hoặc quá muộn.

Thí dụ

Hãy tưởng tượng có một phương thức trong khung phân tích một số:

decimal math.parse(string t)

Nó không có tính minh bạch tham chiếu, bởi vì nó phụ thuộc vào:

  • Biến môi trường chỉ định hệ thống đánh số, đó là Cơ sở 10 hoặc một cái gì đó khác.

  • Biến trong maththư viện chỉ định độ chính xác của các số cần phân tích. Vì vậy, với giá trị của 1, phân tích chuỗi "12.3456"sẽ cung cấp 12.3.

  • Văn hóa, trong đó xác định định dạng dự kiến. Ví dụ, với fr-FR, phân tích cú pháp "12.345"sẽ cung cấp 12345, bởi vì ký tự phân tách nên ,, không phải.

Hãy tưởng tượng sẽ dễ dàng hay khó khăn như thế nào khi làm việc với phương pháp như vậy. Với cùng một đầu vào, bạn có thể có các kết quả hoàn toàn khác nhau tùy thuộc vào thời điểm bạn gọi phương thức, bởi vì một cái gì đó, ở đâu đó đã thay đổi biến môi trường hoặc chuyển văn hóa hoặc đặt độ chính xác khác. Đặc tính không xác định của phương pháp sẽ dẫn đến nhiều lỗi hơn và ác mộng gỡ lỗi nhiều hơn. Gọi math.parse("12345")và nhận 5349như một câu trả lời vì một số mã song song đang phân tích số bát phân không tốt.

Làm thế nào để khắc phục phương pháp rõ ràng bị hỏng này? Bằng cách giới thiệu minh bạch tham chiếu. Nói cách khác, bằng cách loại bỏ trạng thái toàn cầu và di chuyển mọi thứ đến các tham số của phương thức:

decimal math.parse(string t, base=10, precision=20, culture=cultures.en_us)

Bây giờ phương thức này là thuần túy, bạn biết rằng bất kể khi bạn gọi phương thức, nó sẽ luôn tạo ra kết quả tương tự cho cùng một đối số.


4
Chỉ là một phụ lục: tính minh bạch tham chiếu áp dụng cho tất cả các biểu thức trong một ngôn ngữ, không chỉ các chức năng.
vườn

3
Lưu ý rằng có những hạn chế về mức độ minh bạch của bạn. Làm cho packet = socket.recv()tham chiếu minh bạch thay vì đánh bại điểm của hàm.
Đánh dấu

1
Nên là văn hóa = văn hóa.invariant. Trừ khi bạn muốn vô tình tạo ra phần mềm chỉ hoạt động đúng ở Mỹ.
dùng253751

@immibis: hm, câu hỏi hay. Các quy tắc phân tích cú pháp để làm invariantgì? Trong khi đó, chúng giống như trong en_us, trong trường hợp nào, tại sao lại làm phiền, hoặc chúng tương ứng với một quốc gia khác, trong trường hợp nào, tại sao và tại sao nước này thay vì en_us, hoặc chúng có các quy tắc cụ thể không phù hợp với bất kỳ quốc gia nào , đó sẽ là vô ích. Thực sự không có câu trả lời đúng nào của người Viking giữa 12,345.6712 345,67: bất kỳ quy tắc mặc định nào của Vương quốc Anh sẽ làm việc cho một số quốc gia và sẽ không hoạt động cho những người khác.
Arseni Mourzenko

3
@ArseniMourzenko Nó thường là "mẫu số chung thấp nhất" và tương tự như cú pháp mà nhiều ngôn ngữ lập trình sử dụng (cũng là bất biến văn hóa). 12345phân tích như 12345, 12 345hay 12,345hoặc 12.345là một lỗi. 12.345được phân tích dưới dạng số dấu phẩy động bất biến luôn mang lại 12.345, theo quy ước sử dụng ngôn ngữ lập trình. làm dấu phân cách thập phân. Các chuỗi được sắp xếp theo các điểm mã Unicode và phân biệt chữ hoa chữ thường. Và như thế.
dùng253751

11

Bạn có thường thêm điểm dừng vào một điểm trong mã của mình và chạy ứng dụng trong trình gỡ lỗi để tìm ra điều gì đang xảy ra không? Nếu bạn làm như vậy, phần lớn là do bạn không sử dụng độ trong suốt tham chiếu (RT) trong các thiết kế của mình. Và vì vậy phải chạy mã để tìm ra những gì nó làm.

Toàn bộ vấn đề đối với RT là mã có tính quyết định cao, tức là bạn có thể đọc mã và tìm ra những gì nó làm, mọi lúc, cho cùng một bộ đầu vào. Khi bạn bắt đầu thêm các biến đột biến, một số biến có phạm vi ngoài một hàm duy nhất, bạn không thể chỉ đọc mã. Mã như vậy phải được thực thi, trong đầu của bạn hoặc trong trình gỡ lỗi, để tìm ra cách nó thực sự hoạt động.

Mã càng đơn giản để đọc và suy luận, thì càng đơn giản để duy trì và phát hiện ra các lỗi, vì vậy nó giúp tiết kiệm thời gian và tiền bạc cho bạn và chủ nhân của bạn.


10
"Khi bạn bắt đầu thêm các biến đột biến, một số biến ngoài một hàm duy nhất, bạn không thể chỉ đọc mã, bạn phải thực thi nó, trong đầu hoặc trong trình gỡ lỗi, để tìm ra cách nó thực sự hoạt động. ": Điểm tốt. Nói cách khác, độ trong suốt tham chiếu không chỉ có nghĩa là một đoạn mã sẽ luôn tạo ra kết quả tương tự cho cùng một đầu vào, mà còn kết quả được tạo ra là tác động duy nhất của đoạn mã đó, không có mặt khác, ẩn hiệu ứng như thay đổi một số biến đã được xác định ở xa trong một mô-đun khác.
Giorgio

Đó là một điểm tốt. Tôi có một chút vấn đề với mã đơn giản hơn là đọc / đối số lý do , vì đơn giản hơn để đọc hoặc lý do là một thuộc tính hơi mơ hồ và chủ quan của mã.
Eyal Roth

Khi bạn bắt đầu thêm vào các biến đột biến, một số biến có phạm vi ngoài một hàm duy nhất nhưng tại sao thao tác gán lại không được khuyến khích ngay cả khi phạm vi biến là cục bộ của hàm?
rahulaga_dev

9

Mọi người vứt bỏ thuật ngữ "dễ lý luận hơn", nhưng không bao giờ giải thích điều đó có nghĩa là gì. Hãy xem xét ví dụ sau:

result1 = foo("bar", 12)
// 100 lines of code
result2 = foo("bar", 12)

result1result2giống hay khác nhau? Không có tính minh bạch tham chiếu, bạn không có ý tưởng. Bạn phải thực sự đọc phần thân của foođể đảm bảo, và có thể phần thân của bất kỳ hàm nào foogọi, v.v.

Mọi người không nhận thấy gánh nặng này bởi vì họ đã quen với nó, nhưng nếu bạn làm việc trong một môi trường hoàn toàn hoạt động trong một hoặc hai tháng thì quay lại bạn sẽ cảm thấy nó, và đó là một vấn đề rất lớn .

Có rất nhiều cơ chế bảo vệ mà mọi người làm để giải quyết vấn đề thiếu minh bạch tham chiếu. Ví dụ nhỏ của tôi, tôi có thể muốn giữ result1lại trong bộ nhớ, vì tôi không biết liệu nó có thay đổi hay không. Sau đó, tôi có mã với hai trạng thái: trước result1được lưu trữ và sau. Với tính minh bạch tham chiếu, tôi chỉ có thể tính toán lại một cách dễ dàng, miễn là việc tính toán lại không tốn thời gian.


1
Bạn nói rằng tính minh bạch tham chiếu cho phép bạn lập luận về kết quả của các cuộc gọi đến foo () và biết liệu result1result2đều giống nhau. Một khía cạnh quan trọng khác là nếu foo("bar", 12)trong suốt về mặt tham chiếu, thì bạn không cần phải tự hỏi liệu cuộc gọi này có tạo ra một số hiệu ứng ở nơi nào khác không (đặt một số biến? Xóa một tệp? Sao cũng được).
Giorgio

"Tính toàn vẹn tham chiếu" duy nhất mà tôi quen thuộc liên quan đến cơ sở dữ liệu quan hệ.
Đánh dấu

1
@Mark Đó là một lỗi đánh máy. Karl có nghĩa là minh bạch tham chiếu, như là rõ ràng từ phần còn lại của câu trả lời của mình.
Andres F.

6

Tôi muốn nói: tính minh bạch tham chiếu không chỉ tốt cho lập trình chức năng mà còn cho tất cả những người làm việc với các chức năng vì nó tuân theo nguyên tắc ít gây ngạc nhiên nhất.

Bạn có một chức năng và có thể lý do tốt hơn về những gì nó làm bởi vì không có yếu tố bên ngoài nào bạn cần tính đến, đối với một đầu vào nhất định, đầu ra sẽ luôn giống nhau. Ngay cả trong ngôn ngữ bắt buộc của tôi, tôi cố gắng tuân theo mô hình này càng nhiều càng tốt, điều tiếp theo về cơ bản tự động theo sau là: các hàm nhỏ dễ hiểu thay vì các hàm 1000+ khủng khiếp mà tôi đôi khi chạy.

Những chức năng lớn đó làm nên điều kỳ diệu và tôi sợ chạm vào chúng vì chúng có thể phá vỡ một cách ngoạn mục.

Vì vậy, các hàm thuần túy không phải là thứ chỉ dành cho lập trình hàm, mà là cho mọi chương trình.

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.