Tính toán nếu một hàm là thuần túy


11

Theo Wikipedia:

Trong lập trình máy tính, một hàm có thể được mô tả là thuần túy nếu cả hai câu lệnh này về hàm giữ: Hàm luôn đánh giá cùng một giá trị kết quả được đưa ra cùng một 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. Đánh giá kết quả không gây ra bất kỳ tác dụng phụ hoặc đầu ra có thể quan sát được về mặt ngữ nghĩa, chẳng hạn như đột biến của các đối tượng có thể thay đổi hoặc đầu ra cho các thiết bị I / O.

Tôi tự hỏi nếu có thể viết một hàm tính toán nếu một hàm là thuần túy hay không. Mã ví dụ trong Javascript:

function sum(a,b) {
    return a+b;
}

function say(x){
    console.log(x);
}

isPure(sum) // True
isPure(say) // False

7
Đây có thể là ứng cử viên cho Sàn giao dịch Khoa học Máy tính . Điều này thiên về lý thuyết ("có thể") hơn là thực tế và thiết kế ... Nó hơi xa so với ken của tôi.

... và mặc dù nó là "có thể" và "lý thuyết" rất có khả năng là một câu trả lời thực sự cho nó (phù hợp với Q & A) thậm chí có thể liên quan đến một bằng chứng ... một lần nữa đưa nó trở lại thế giới khoa học máy tính .

Tôi nghĩ bạn có thể xác định xem một hàm có thuần túy hay không bằng cách xem loại hàm được gọi trong định nghĩa của nó. Ý tôi là, bạn có thể định nghĩa độ tinh khiết bằng cách cảm ứng trên cấu trúc của các chức năng.
Giorgio

7
Không thể thực hiện được nếu không có các bản hack phản chiếu dành riêng cho nền tảng. Nếu một chức năng là một hộp đen, không có thí nghiệm nào có thể chứng minh nó là thuần túy. Ví dụ, nếu có một cái gì đó giống như if (rand(1000000)<2) return WRONG_ANSWER, việc thăm dò chức năng nhiều lần cho một hành vi nhất quán sẽ không giúp ích. Nhưng, nếu bạn có quyền truy cập vào định nghĩa hàm, bằng chứng là không đáng kể.
SK-logic

1
@ user470365 Từ định nghĩa của hàm thuần túy - "Đánh giá kết quả không gây ra bất kỳ tác dụng phụ hoặc đầu ra có thể quan sát được về mặt ngữ nghĩa, chẳng hạn như đột biến của các đối tượng có thể thay đổi hoặc đầu ra cho các thiết bị I / O." - Bất cứ điều gì ghi vào IO là không tinh khiết theo định nghĩa. Trong ví dụ này, saycác cuộc gọi console.logkhông trong sạch saycũng không tinh khiết.

Câu trả lời:


17

Vâng, nó là có thể, tùy thuộc vào ngôn ngữ.

Trong JavaScript, bạn có thể biết liệu một hàm có thuần túy theo các tiêu chí sau không:

  • Nó chỉ đọc các tham số và địa phương;

  • Nó chỉ viết người địa phương;

  • Trên những người không phải người địa phương, nó chỉ gọi các hàm thuần túy;

  • Tất cả các chức năng mà nó gọi hoàn toàn là thuần túy, vd toString; và

  • Nó chỉ viết thuộc tính của người địa phương nếu họ không bí danh không phải người địa phương.

Bí danh không thể xác định trong JavaScript trong trường hợp chung, bởi vì bạn luôn có thể tra cứu các thuộc tính của một đối tượng một cách linh hoạt ( object["property"]). Với điều kiện bạn không bao giờ làm điều đó, và bạn có nguồn gốc của toàn bộ chương trình, thì tôi nghĩ vấn đề có thể giải quyết được. Bạn cũng sẽ cần thông tin về chức năng riêng nào có tác dụng phụ, chẳng hạn như console.loghoặc hầu hết mọi thứ liên quan đến DOM.

Thuật ngữ tinh khiết tinh ranh cũng có thể sử dụng một số làm rõ. Ngay cả trong một ngôn ngữ lập trình chức năng mạnh mẽ, được gõ tĩnh, thuần túy, trong đó tất cả các chức năng được minh bạch tham chiếu, một chức năng vẫn có thể không kết thúc. Vì vậy, khi chúng ta nói về id :: a -> a, những gì chúng ta thực sự nói không phải là:

Cho một số giá trị của loại a, hàm idtạo ra một giá trị của loại a.

Nhưng đúng hơn là:

Đưa ra một số giá trị của loại hình a, chức năng idnào không tạo ra một giá trị đó là không loại a.

Bởi vì một thực hiện hợp lệ iderror "Not implemented!". Như Peteris chỉ ra, tính phi nghĩa này có thể được coi là một loại tạp chất. Koka là một ngôn ngữ lập trình chức năng, với cú pháp được mô hình hóa trên JavaScript, có thể suy ra các hiệu ứng có thể xảy ra như phân kỳ (không phân cực), minh bạch tham chiếu, ném ngoại lệ và hành động I / O.


+1 - Đưa ra câu trả lời của Peteris đã nhận được rất nhiều sự
ủng hộ

Tôi cho rằng bạn sẽ cần thêm "Nó chỉ gọi các hàm thuần túy" vào danh sách các tiêu chí.
Greg Hewgill

1
@GregHewgill: Bắt tốt. Tôi cập nhật câu trả lời cho phù hợp. Sẽ tốt hơn nếu gọi các chức năng đột biến trên người dân địa phương, miễn là chúng không có tác dụng phụ. Càng thuần túy thì quá tải một thuật ngữ
Jon Purdy

Bạn cũng cần kiểm tra xem toStringcó thuần cho bất kỳ đối tượng nào bạn sử dụng dưới dạng chuỗi không.
Oleg V. Volkov

Tôi không nghĩ câu trả lời này là đúng, bởi vì chỉ có một tập hợp các tình huống mà bạn thực sự có thể đưa ra những quyết định này. Hãy xem xét: chức năng này là tinh khiết? function a (o) { return o.method(); }- chúng tôi thực sự không thể trả lời điều này, vì nó phụ thuộc vào thông số nào ođược thông qua. Ngoài ra, chúng tôi không thể giải thích điều gì xảy ra nếu một chức năng thuần túy được chứng nhận trước đó được thay đổi thành triển khai không thuần túy, đây luôn là vấn đề tiềm ẩn với javascript.
Jules

11

Không. Bạn có thể dễ dàng kiểm tra xem một chức năng chỉ thực hiện các hoạt động "an toàn thuần túy", như được mô tả trong câu trả lời của Jon Purdy, nhưng đó là IMO không đủ để trả lời câu hỏi.

Hãy xem xét chức năng này:

function possiblyPure(x) {
    if (someCheck(x)) {
        return x+1; // pure code path
    }
    else {
        console.log("I'm so unpure..."); // unpure code path
    }
}

Rõ ràng, nếu không someCheckchắc chắn, thì cũng vậy possiblyPure. Nhưng, nếu someChecklà thuần túy và trả về truecho mọi giá trị có thể có x, possiblyPurelà thuần túy, vì đường dẫn mã không rõ ràng là không thể truy cập được!

Và đây là phần khó: xác định có someChecktrả về đúng hay không cho mọi đầu vào có thể. Cố gắng trả lời câu hỏi đó ngay lập tức sẽ đưa bạn vào vương quốc của vấn đề tạm dừng và những vấn đề tương tự không thể giải quyết được.

EDIT: Bằng chứng là không thể

Có một số yếu tố không chắc chắn hoặc không phải là một hàm thuần túy phải chấm dứt trên mọi đầu vào có thể. Nhưng trong cả hai trường hợp, vấn đề tạm dừng có thể được sử dụng để chỉ ra rằng việc kiểm tra độ tinh khiết là không thể.

Trường hợp A) Nếu một hàm thuần túy được yêu cầu chấm dứt trên mọi đầu vào có thể, bạn phải giải quyết vấn đề tạm dừng để xác định xem hàm đó có thuần túy hay không. Vì điều này được biết là không thể, theo định nghĩa này, độ tinh khiết không thể được tính toán.

Trường hợp B) Nếu một hàm thuần túy được phép không chấm dứt trên một số đầu vào, chúng ta có thể xây dựng một cái gì đó tương tự: Giả sử rằng isPure(f)tính toán nếu flà một chuỗi xác định một hàm thuần túy.

function halts(f) {
   var fescaped = f.replace(/\"/g, '\\"');
   var upf = 'function() { '+f+'("'+fescaped+'\); console.log("unpure"); }';
   return isPure(upf);
}

Bây giờ isPurephải xác định xem có fdừng lại trên nguồn của chính nó làm đầu vào hay không. Nếu nó dừng lại, upflà không chắc chắn; nếu nó không chấm dứt, upfiff fthuần túy là thuần túy.

Nếu isPurehoạt động như mong đợi (trả về kết quả chính xác và chấm dứt trên mọi đầu vào), chúng tôi sẽ giải quyết vấn đề tạm dừng (*)! Vì điều này được biết là không thể, isPurekhông thể tồn tại.

(*) cho các hàm JavaScript thuần túy, cũng đủ để giải quyết nó cho máy turing.


3
Thật. Luôn luôn có thể thực hiện một phân tích bảo thủ - để kiểm tra xem một hàm có chắc chắn là thuần túy không, nhưng không thể kiểm tra xem nó có chắc chắn không thuần túy hay không.
SK-logic

Nhiều trường hợp có thể quyết định một cách tầm thường - những chức năng thuần túy được mô tả bởi Jon Purdy hoặc các chức năng không rõ ràng mà vô điều kiện làm điều gì đó bẩn thỉu; nhưng nói chung, người ta có thể xây dựng các trường hợp không thể giải quyết được.
user281377

1

Câu hỏi stackoverflow này có câu trả lời của yfeldblum có liên quan ở đây. (Và có một lý do vì một số lý do mà tôi không thể hiểu được. Nó có phải là nghi thức xấu đối với việc nâng cấp một cái gì đó đã 3 tuổi không?) Ông đưa ra một bằng chứng rằng liệu một chức năng có thuần túy có thể giảm bớt vấn đề tạm dừng trong một nhận xét hay không.

Tôi nghĩ từ quan điểm thực tế, sẽ không quá khó đối với một số ngôn ngữ nếu bạn để chức năng trả về có, không, hoặc có thể. Tôi đã xem một video về Clojure vài ngày trước và người nói đã thực hiện một số trường hợp tạp chất trong một cơ sở mã bằng cách tìm kiếm khoảng 4 chuỗi khác nhau (như "ref"). Do sự nhấn mạnh của Clojure về sự tinh khiết và sự phân biệt của những thứ không trong sạch, nó thật tầm thường, nhưng nó không hoàn toàn chính xác những gì bạn đang tìm kiếm.

Vì vậy, về mặt lý thuyết là không thể, thực tế là có thể nếu bạn điều chỉnh câu hỏi một chút, và tôi nghĩ nó sẽ khó đến mức nào sẽ phụ thuộc rất lớn vào ngôn ngữ. Các ngôn ngữ đơn giản / sạch hơn tập trung vào tính bất biến và phản xạ tốt sẽ dễ dàng hơn.


Tôi nghĩ, nó đã bị hạ cấp vì nó sai. bottomlà một giá trị hạng nhất, hợp lệ, nó không đáng bị phân biệt đối xử theo cách này.
SK-logic

0

Câu hỏi tuyệt vời.

Điều tốt nhất bạn có thể làm trong thực tế, giả sử không có khả năng lắng nghe các hành động i / o để gọi hàm nhiều lần khả thi. Sau đó xem nếu giá trị trả lại là phù hợp.

Nhưng bạn không thể làm điều này nói chung. Có thể cho rằng, các chương trình không tạm dừng là không thuần túy và chúng tôi không thể quyết định vấn đề tạm dừng.


1
-1: Sẽ là quá tầm thường khi viết một hàm vượt qua bài kiểm tra này và bất cứ điều gì ngoài thuần túy.
mattnz

3
Theo logic này, bất kỳ voidchức năng nào sẽ là "thuần túy", rõ ràng là sai.
Greg Hewgill

1
@Greg: Bằng cách mở rộng, void foo (void) cũng sẽ phải thuần túy.
mattnz

0

Không thể trong trường hợp chung. Xem vấn đề tạm dừng . Tóm lại, không thể viết một chương trình, với một hàm tùy ý và đầu vào, xác định xem chương trình sẽ dừng hoặc chạy mãi mãi. Nếu nó chạy mãi mãi, đó không phải là một hàm thuần túy phù hợp với định nghĩa bạn đã đưa ra.


5
Chạy mãi mãi dường như không giảm giá một chức năng phù hợp với tiêu chí của mình cho một chức năng thuần túy.
whatsisname

+1: Có một yêu cầu ngầm định rằng funciuon chấm dứt bởi "Hàm luôn luôn đánh giá cùng một giá trị kết quả cho ...."
mattnz

2
Chạy liên tục mà không sửa đổi bất kỳ trạng thái nào là hoàn toàn "thuần túy". Nhưng, tất nhiên, nó là một vấn đề thuật ngữ ở đây.
SK-logic

@mattnz, một hàm như vậy sẽ luôn luôn đánh giá giá bottomtrị.
SK-logic

1
Tôi có thể thấy vấn đề thuật ngữ xuất hiện ở đâu. Trong một số diễn giải, chức năng "thuần túy" là một chức năng mang tính quyết định cũng như không bao giờ giao tiếp bất kỳ trạng thái hoặc giá trị nào với bên ngoài trong quá trình thực thi. Trong các giải thích khác, tạm dừng được thêm vào các yêu cầu. Với cách hiểu đầu tiên, thật dễ dàng để xác định xem một hàm có thuần túy hay không: một máy thực thi một ngôn ngữ cụ thể phải có khả năng xác định xem một chương trình trong ngôn ngữ đó có thực hiện bất kỳ giao tiếp nào với bên ngoài hay không.
rwong
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.