Tại sao Today () là một ví dụ về hàm không tinh khiết?


38

Có vẻ như, khi đọc một cái gì đó giống như bài viết trên Wikipedia này về "các hàm thuần túy" , chúng liệt kê Today()như một ví dụ về hàm không tinh khiết nhưng nó có vẻ khá thuần đối với tôi. Có phải vì không có đối số đầu vào chính thức? Tại sao thời gian thực tế trong ngày không được coi là "đầu vào của hàm" trong trường hợp đó nếu bạn đưa ra cùng một đầu vào, tức là thực hiện today()hai lần cùng một lúc hoặc quay ngược thời gian để thực hiện lại (có thể là giả thuyết: )), đầu ra sẽ là cùng một lúc. Today()không bao giờ cung cấp cho bạn một số ngẫu nhiên. nó luôn luôn cung cấp cho bạn thời gian trong ngày.

Bài viết trên Wikipedia cho biết "những thời điểm khác nhau sẽ mang lại kết quả khác nhau" nhưng điều đó giống như nói về sự khác biệt x sin(x)sẽ mang đến cho bạn những tỷ lệ khác nhau. Và sin(x)là ví dụ của họ về một hàm thuần túy.


8
Nếu bạn vượt qua trong thời gian trong ngày, chức năng sẽ làm gì?
JB King

1
Tôi hy vọng nó sẽ cung cấp cho bạn thời gian trong ngày. (không phải là chức năng hữu ích nhất). Nhưng nó không có bất kỳ tranh luận nào, mà tôi nghĩ là gốc rễ của câu trả lời.
Brad

3
Bạn có thể dự đoán đầu ra của nó (dựa trên các tham số đầu vào bạn cung cấp) không?
Daniel B

1
@DanielB Không có khả năng dự đoán cho tham số đầu vào vắng mặt / null. Điều duy nhất tôi có thể làm là nhìn vào đồng hồ đeo tay của tôi (jk điện thoại di động của tôi).
Brad

"Tại sao thời gian thực tế trong ngày không được coi là" đầu vào của chức năng "" Về cơ bản, đây là vấn đề mà các đơn vị cố gắng giải quyết. Các chức năng thuần túy chỉ có thể dựa trên đầu vào của chúng & không thể có tác dụng phụ. Nếu bạn biến "trạng thái của thế giới trước tôi" thành đầu vào và "trạng thái của thế giới sau tôi" một phần của giá trị trả về và vượt qua các trạng thái thế giới này thông qua chương trình của bạn, một lần nữa bạn có thể trở nên thuần khiết.
Sean McS Something 24/1/13

Câu trả lời:


103

Có phải vì không có đối số đầu vào chính thức?

Đó là bởi vì đầu ra phụ thuộc vào một cái gì đó không phải là đầu vào, cụ thể là thời gian hiện tại.

Tại sao thời gian thực tế trong ngày không được coi là "đầu vào của hàm"

Bởi vì bạn đã không vượt qua nó như một tham số. Nếu bạn đã truyền nó dưới dạng tham số, hàm sẽ trở thành hàm nhận dạng vào các ngày, điều này khá vô dụng. Toàn bộ điểm của Today()hàm là xuất ra thứ gì đó phụ thuộc vào giá trị bên ngoài và liên tục thay đổi (thời gian).

Ưu điểm của các hàm thuần túy là hành vi của chúng hoàn toàn có thể tái tạo và xác định, giúp dễ dàng có bằng chứng chính thức và đảm bảo cứng. Họ luôn làm điều tương tự. Today()hoàn toàn ngược lại: nó luôn luôn (cho phép độ chi tiết thời gian) làm một cái gì đó khác biệt.


2
Vì vậy, mặc dù thời gian của thực tế là một loại đầu vào, bởi vì nó không được đưa ra như một đầu vào và nó nằm ngoài sự kiểm soát của chức năng (cả bên trong chức năng và bên ngoài sự kiểm soát của bất cứ ai đang gọi Today()) đều Today()không trong sạch. Các Today()chức năng có thể là một chút của một ví dụ ngớ ngẩn. Thích hợp hơn có thể là một số Count()chức năng. Cho cùng một số lượng vật phẩm cần đếm Count()sẽ luôn trả về cùng một số, nhưng vì nó nằm ngoài phạm vi của Count()nó là không tinh khiết.
Brad

1
@brad đó là một phần của một khu vực màu xám - có một đối số thực tế ngầm định - mảng hoặc danh sách. Đưa ra một danh sách bất biến và cùng một đối số mỗi lần nó sẽ luôn trả về cùng một giá trị.
Tối đa

34
"Thời gian của thực tế là một loại đầu vào" - có; thật vậy, trạng thái toàn cầu hoàn toàn có sẵn (nghĩa là 'loại đầu vào') cho tất cả các chức năng, nhưng nếu chúng phụ thuộc vào nó cho kết quả của chúng thì chúng không trong sạch!
AakashM

4
@Brad count()trên hầu hết các ngôn ngữ lập trình chắc chắn là thuần túy. Nó có một giá trị đầu vào rõ ràng: bộ sưu tập có số lượng bạn muốn. Đừng nhầm lẫn bởi một cú pháp như myCollection.count(); đó chỉ là đường cho count(myCollection).
Andres F.

Câu trả lời tuyệt vời như mọi khi, nhưng nó không bao gồm rõ ràng các biến miễn phí bất biến. Chúng không phải là một đầu vào cho hàm - không được truyền dưới dạng tham số - nhưng hàm phụ thuộc vào chúng ngay cả khi nó vẫn trong suốt tham chiếu.

24

sin(x)sẽ luôn trả về cùng một giá trị, miễn là xgiữ nguyên. Today()có thể trả về các kết quả khác nhau theo thời gian vì nó phụ thuộc vào các giá trị ngoài tầm kiểm soát của bạn . Ví dụ: nếu một cái gì đó nằm ngoài sự kiểm soát của chương trình của bạn thay đổi nội bộ của hệ thống trong $current_datetime khi chương trình của bạn đang chạy, Today()sẽ đột nhiên mang lại kết quả khác nhau.


"Sẽ luôn trả về một giá trị khác" là một chút ... từ ngữ không trong sạch . Wikipedia nói "trả về ngày hiện tại trong tuần" có nghĩa là các giá trị thu được vào thứ Hai sẽ không khác nhau
gnat

7
@gnat: Đúng, trừ khi có gì đó bên ngoài chương trình của bạn thay đổi lịch nội bộ của máy tính để nó đột nhiên nghĩ rằng đó là thứ Năm. Sau đó, cuộc gọi Today()sẽ trở lại "Thứ năm" vào thứ Hai.
Thất vọngWithFormsDesigner

3
@gnat Chà, nó sẽ không luôn trả về một giá trị khác (hầu như không có chức năng hữu ích nào). Nhưng, giống như hầu hết các hàm không tinh khiết, giá trị trả về có thể thay đổi ngay cả trong khi thực hiện một chương trình duy nhất (ví dụ: nếu nó chạy qua đêm).

3
@delnan: Vâng, đó là nguyên nhân của các tác giả kịch bản cơ sở dữ liệu ngây thơ! : P "Nhưng làm thế nào nó có thể bỏ lỡ 300 bản ghi? Kịch bản hoạt động tốt khi tôi kiểm tra nó vào sáng hôm qua!"
Thất vọngWithFormsDesigner

@delnan chắc chắn rồi. Tôi chỉ chỉ ra rằng việc luôn luôn sử dụng từ ngữ ban đầu (được sửa trong câu trả lời của phiên bản hiện tại thành có thể ) có phần không chính xác
gnat

13

Hôm nay () là một hàm không tinh khiết vì kết quả của nó phụ thuộc vào thứ mà bạn không cung cấp cho nó; Cụ thể, thời gian hệ thống hiện tại. Do đó, kết quả của nó không mang tính quyết định khi chỉ dựa trên các đầu vào được cung cấp khi gọi.

Một chức năng thuần túy sẽ là int Add(int a, int b) {return a + b;}. Hàm này chỉ hoạt động với những gì nó được cung cấp và không sử dụng dữ liệu trạng thái bên ngoài nào khác. Kết quả tự nhiên của việc này là bạn có thể Add(2,2)và nhận được 4 từ giờ cho đến hết thời gian. Ngoài ra, do chức năng không thay đổi bất kỳ trạng thái bên ngoài nào (nó không có "tác dụng phụ"), nên Add () ing 2 và 2 từ giờ cho đến khi hết thời gian sẽ không thay đổi bất cứ điều gì khác trong hệ thống, trừ khi bạn gán kết quả của hàm cho một biến hoặc sử dụng giá trị để cập nhật trạng thái (đây không phải là thao tác được thực hiện bởi chính hàm đó). Hầu như tất cả các hoạt động toán học cổ điển là các hàm thuần túy và có thể được thực hiện như vậy.

Hôm nay (), mặt khác, có thể tạo ra cùng một giá trị khi được gọi hai lần liên tiếp, nhưng không được gọi liên tục trong vài ngày. Điều này là do nó phụ thuộc vào dữ liệu trạng thái bên ngoài mà bạn không cung cấp dưới dạng tham số cho hàm. Do đó, trong phạm vi của chương trình, không thể kiểm soát kết quả của hàm Today (). Nó sẽ tạo ra một giá trị nhất định vào một ngày nhất định và sẽ không bao giờ tạo ra giá trị đó vào bất kỳ ngày nào khác, trừ khi bạn thay đổi đồng hồ hệ thống của máy tính chạy trên đó (một thay đổi thường xảy ra bên ngoài ranh giới của chương trình).

Một chức năng không tinh khiết không nhất thiết là một điều xấu; Các chức năng không tinh khiết được yêu cầu, ngay cả trong các ngôn ngữ chức năng, để tương tác với bất kỳ thứ gì bên ngoài ranh giới của chương trình, chẳng hạn như lưu trữ dữ liệu, đường ống truyền thông, màn hình UI, thiết bị ngoại vi, v.v. Một chương trình không làm bất kỳ điều gì trong số này là chương trình đó là hạn chế mạnh mẽ trong tiện ích của nó; Tôi thậm chí sẽ đi xa đến mức gọi một chương trình tầm thường như vậy, vì không có bất kỳ phương tiện nào để chấp nhận đầu vào hoặc bất kỳ con đường nào để thông báo cho bạn về đầu ra của nó, nó cũng có thể không làm gì cả. Các chương trình được viết bằng ngôn ngữ chức năng chỉ có thể có đầu vào được cung cấp bởi bộ thực thi và tạo ra một đầu ra được báo cáo cho bộ thực thi mà không có bất kỳ phương thức không rõ ràng nào được xác định rõ ràng, nhưng đó là do bộ thực thi đang trừu tượng hóa tất cả các chi tiết không hoạt động này trong một hệ thống máy tính không hoàn hảo,

Nó chỉ đơn giản là một điều rất tốt để biết chức năng nào bạn đang sử dụng là thuần túy và chức năng nào không, để bạn có thể đưa ra quyết định tốt về cách sử dụng chúng. Các chức năng không tinh khiết, bởi vì chúng làm mọi thứ hoặc phụ thuộc vào những thứ không rõ ràng từ việc sử dụng của chúng, có thể hành xử không thể đoán trước chỉ có kiến ​​thức về việc sử dụng. Kiến thức sâu hơn về mục đích của chức năng, và do đó, những gì nó cần từ hoặc làm cho trạng thái bên ngoài, được yêu cầu để đặt một hệ thống sử dụng nó ở trạng thái nhất quán và do đó để mong đợi một kết quả xác định.


8

Có vẻ như khá rõ ràng rằng chức năng này thất bại trong bài kiểm tra đầu tiên về độ tinh khiết được đưa ra ở ngay đầu trang đó:

  1. Hàm luôn đánh giá cùng một giá trị kết quả được đưa ra cùng (các) giá trị đối số. Giá trị kết quả chức năng không thể phụ thuộc vào bất kỳ thông tin hoặc trạng thái ẩn nào có thể thay đổi khi tiến hành thực hiện chương trình hoặc giữa các lần thực hiện khác nhau của chương trình, cũng không thể phụ thuộc vào bất kỳ đầu vào bên ngoài nào từ các thiết bị I / O.

Lưu ý rằng vì không có đối số, nên chỉ có một bộ giá trị đối số có thể có - bộ trống. Và hàm này có thể và trả về các kết quả khác nhau cho cùng một 'giá trị đối số'.

Hơn nữa, hàm giá trị kết quả không phụ thuộc vào "ẩn ... trạng thái đó có thể thay đổi khi tiền thu được thực hiện chương trình". Thế là thất bại.


@ JörgWMittag Tôi không chắc chắn nơi tôi khẳng định rằng một hàm không có đối số có thể trả về giá trị.
AakashM

Rối não. Tôi đọc "chỉ có một bộ giá trị trả về ".
Jörg W Mittag

8

() => 1sẽ là một hàm thuần túy, vì nó luôn trả về 1. Today()có thể trả về "Thứ hai" hoặc "Thứ ba" hoặc gần như bất kỳ giá trị nào khác.

Một cách khác để nghĩ về nó là các hàm thuần túy không phụ thuộc vào trạng thái. Thế giới thường được coi là nhà nước. Bạn cần biết trạng thái của thực tế để biết ngày hôm nay là ngày gì.

Tuy nhiên, bạn không cần phải biết bất cứ điều gì đặc biệt về tình trạng của thế giới để biết nó sin(x)là gì . Và bao giờ gọi sin(x)cho một cho trước xsẽ trả lại cùng một giá trị.


Wikipedia nói "trả về ngày hiện tại trong tuần", nghĩa là nó có thể trở lại vào thứ Hai, thứ Ba, v.v. nhưng không phải là "1/23/2013" hay "1/24/2013"
gnat

7
@gnat: Đã cập nhật, nhưng sự khác biệt không thực sự quan trọng.
Guvante

2

Date(timestamp)sẽ là một chức năng thuần túy. Bởi vì sự bình dị của nó. Và bởi vì sẽ không có tác dụng phụ.

Today()có thể thay đổi kết quả của nó tùy thuộc vào khi bạn gọi nó. Đó là những gì làm cho nó không tinh khiết. Nó không bình thường. Nó không có tác dụng phụ mặc dù, nhưng điều đó không làm cho nó tinh khiết.


2

Đây là một mã giả nhỏ mà tôi nghĩ đến khi thảo luận về các hàm thuần túy

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Nếu nó chạy vô thời hạn và không bao giờ có thể kích hoạt khẳng định, thì đó là một chức năng thuần túy. Hơn nữa, nếu bạn có một hàm sử dụng args, thì hãy sửa đổi một chút ....

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Nếu bạn có thể sử dụng nó sau mỗi lần gán biến trong ứng dụng của mình và nó không thay đổi kết quả trong ứng dụng của bạn và nó không bao giờ có thể thất bại trong việc xác nhận, thì đó là một chức năng thuần túy.


2

Đầu tiên, không có thứ gọi là hàm không có đối số (hoặc một mảng không có chỉ mục hoặc bản đồ không có khóa). Đây là đặc tính xác định của hàm để ánh xạ một hoặc nhiều giá trị đối số sang giá trị khác.

Do đó, todaykhông phải là một chức năng nào cả, do đó không có chức năng thuần túy. Hoặc chúng tôi có thể giải thích cú pháp

today()

một chút để nó có nghĩa là

today   ()      -- today, applied to the value ()

Trong Haskell, ví dụ, điều này sẽ hợp lệ:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

bởi vì có một loại () với một giá trị ().

Câu hỏi là duy nhất, làm thế nào có thể todaytính ngày trong tuần, nếu nó chỉ có ()? Nó chỉ là không thể nếu không đọc bộ đếm thời gian hệ thống, trực tiếp hoặc thông qua các chức năng không tinh khiết của người trợ giúp.

Bộ đếm thời gian hệ thống là một ví dụ tuyệt vời cho trạng thái toàn cầu.


1

Vấn đề với today()là nó có thể mang lại một kết quả khác nếu được gọi hai hoặc nhiều lần trong một hàm.

Đây là một ví dụ mã, có thể giới thiệu một lỗi.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

Có thể trong ví dụ trên. Đó là iftuyên bố thứ hai sẽ không thực thi. Ngay cả khi người đầu tiên đã làm. Để lại một tài nguyên trong một trạng thái xấu.


1

Để trở thành một hàm thuần túy, việc cung cấp các tham số giống nhau phải cho cùng một kết quả mỗi lần.

Mỗi lần chúng tôi gọi Today(), chúng tôi sẽ cung cấp cho nó các tham số giống nhau (không có) và không nhất thiết phải có cùng kết quả (Thứ Hai, Thứ Ba, v.v.).


4
điều này dường như chỉ lặp lại điểm được thực hiện và giải thích trong một câu trả lời hàng đầu đã được đăng khoảng hai năm trước. Rất khó để trả lời câu hỏi hai năm tuổi với nội dung như vậy
gnat

1
Tôi không quá quen thuộc với cách hoạt động của stackexchange, nhưng tôi đã hiểu rằng vì đây là câu hỏi hàng đầu mà nó đã bị lỗi. Theo như một điểm lặp lại, tôi nhớ đọc trên meta rằng có thể có nhiều câu trả lời tương tự. Tôi cảm thấy như của tôi là cô đọng và có khả năng hữu ích.
Zantier
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.