Minh bạch tham chiếu là gì?


285

Thuật ngữ minh bạch tham chiếu có nghĩa là gì? Tôi đã nghe nó được mô tả là "nó có nghĩa là bạn có thể thay thế bằng bằng" nhưng điều này có vẻ như là một lời giải thích không thỏa đáng.


1
wow tôi tự hỏi tại sao sự đột ngột tăng lên trong sự phổ biến của câu hỏi này ...
Claudiu

1
@claudia: Tôi không thể nói chắc chắn, nhưng r / haskell có gió và nhiều người cảm thấy Uday, mặc dù khá chính xác, lấy một chút của một nhóm trong cộng đồng.
efrey

6
@efrey Một jibe, có lẽ là vậy. Nhưng, khi các lập trình viên chức năng bắn hạ các ngôn ngữ lập trình cấp bách và các ngôn ngữ chức năng có tác dụng phụ (như Lisp và ML) tuyên bố rằng chúng không minh bạch về mặt tham chiếu, liệu chúng có phải là một nhóm không? Họ có nên ít nhất không nhận được sự thật của họ ngay trước khi làm như vậy?
Uday Reddy

2
@Claudiu Tôi đã đăng nó trên Haskell Reddit và Conal đã tweet nó. Tôi thấy cuộc thảo luận thú vị và nghĩ rằng nó đáng để thảo luận rộng hơn. Tôi đã thu hút sự chú ý đến nhóm của Uday để kích thích một cuộc thảo luận. Tôi đồng ý rằng đôi khi những người kiểm lâm của chúng tôi có thể tự mãn và cần một sản phẩm tốt - hoàn thành tốt cho Uday để cung cấp nó!
chrisdornan

7
@efrey. Thật vậy, đó là lý do tại sao tôi chọn trích dẫn từ Bird và Wadler (ngữ nghĩa học?) Trong bài viết thứ hai của tôi. Những người có kiến ​​thức biết rằng quan niệm phổ biến về tính minh bạch tham chiếu là mơ hồ và có thể không mạch lạc. Nhưng nó chưa bao giờ được giải thích cho cộng đồng lập trình đúng. Hy vọng bài viết của tôi ở đây sẽ làm cho một sự khác biệt.
Uday Reddy

Câu trả lời:


362

Thuật ngữ "minh bạch tham chiếu" xuất phát từ triết học phân tích , nhánh của triết học phân tích các cấu trúc ngôn ngữ tự nhiên, các phát biểu và lập luận dựa trên các phương pháp logic và toán học. Nói cách khác, nó là môn học gần nhất ngoài khoa học máy tính với cái mà chúng ta gọi là ngữ nghĩa lập trình ngôn ngữ . Nhà triết học Willard Quine chịu trách nhiệm khởi xướng khái niệm về tính minh bạch tham chiếu, nhưng nó cũng tiềm ẩn trong cách tiếp cận của Bertrand Russell và Alfred Whitehead.

Tại cốt lõi của nó, "minh bạch tham chiếu" là một ý tưởng rất đơn giản và rõ ràng. Thuật ngữ "người giới thiệu" được sử dụng trong triết học phân tích để nói về điều mà một biểu thức đề cập đến . Nó gần giống như những gì chúng ta muốn nói là "nghĩa" hay "ký hiệu" trong ngữ nghĩa ngôn ngữ lập trình. Sử dụng ví dụ của Andrew Birkett ( bài đăng trên blog ), thuật ngữ "thủ đô của Scotland" dùng để chỉ thành phố Edinburgh. Đó là một ví dụ đơn giản về "người giới thiệu".

Một ngữ cảnh trong câu là "minh bạch tham chiếu" nếu thay thế một thuật ngữ trong ngữ cảnh đó bằng một thuật ngữ khác đề cập đến cùng một thực thể không làm thay đổi nghĩa. Ví dụ

Quốc hội Scotland họp tại thủ đô của Scotland.

có nghĩa giống như

Quốc hội Scotland họp tại Edinburgh.

Vì vậy, bối cảnh "Quốc hội Scotland họp tại ..." là một bối cảnh minh bạch tham chiếu. Chúng ta có thể thay thế "thủ đô của Scotland" bằng "Edinburgh" mà không làm thay đổi ý nghĩa. Nói cách khác, bối cảnh chỉ quan tâm đến những gì thuật ngữ này đề cập đến và không có gì khác. Đó là ý nghĩa trong đó bối cảnh là "minh bạch tham chiếu."

Mặt khác, trong câu,

Edinburgh là thủ đô của Scotland từ năm 1999.

chúng ta không thể thay thế như vậy. Nếu chúng ta làm như vậy, chúng ta sẽ nhận được "Edinburgh đã là Edinburgh từ năm 1999", đó là một điều thú vị để nói, và không truyền đạt ý nghĩa tương tự như câu gốc. Vì vậy, có vẻ như bối cảnh "Edinburgh đã ... từ năm 1999" bị mờ đục (ngược lại với tính minh bạch tham chiếu). Nó rõ ràng quan tâm đến một cái gì đó nhiều hơn những gì thuật ngữ này đề cập đến. Nó là gì?

Những thứ như "thủ đô của Scotland" được gọi là các thuật ngữ xác định và chúng không gây đau đầu cho các nhà logic học và triết học trong một thời gian dài. Russell và Quine đã sắp xếp chúng ra nói rằng chúng không thực sự là "tham chiếu", nghĩa là, thật sai lầm khi nghĩ rằng các ví dụ trên được sử dụng để chỉ các thực thể. Cách hiểu đúng "Edinburgh là thủ đô của Scotland từ năm 1999" là nói

Scotland đã có một thủ đô từ năm 1999 và thủ đô đó là Edinburgh.

Câu này không thể được chuyển thành một câu hạt dẻ. Vấn đề được giải quyết! Quan điểm của Quine là nói rằng ngôn ngữ tự nhiên lộn xộn, hoặc ít nhất là phức tạp, bởi vì nó được tạo ra để thuận tiện cho việc sử dụng thực tế, nhưng các nhà triết học và logic nên mang lại sự rõ ràng bằng cách hiểu chúng đúng cách. Tính minh bạch tham chiếu là một công cụ được sử dụng để mang lại ý nghĩa rõ ràng như vậy .

Tất cả những điều này có liên quan gì đến lập trình? Thật ra không nhiều lắm. Như chúng ta đã nói, tính minh bạch tham chiếu là một công cụ được sử dụng để hiểu ngôn ngữ, nghĩa là trong việc gán nghĩa . Christopher Strachey , người sáng lập lĩnh vực ngữ nghĩa ngôn ngữ lập trình, đã sử dụng nó trong nghiên cứu về ý nghĩa của mình. Bài viết nền tảng của ông " Các khái niệm cơ bản trong ngôn ngữ lập trình " có sẵn trên web. Đó là một bài báo đẹp và mọi người đều có thể đọc và hiểu nó. Vì vậy, xin vui lòng làm như vậy. Bạn sẽ được giác ngộ nhiều. Ông giới thiệu thuật ngữ "minh bạch tham chiếu" trong đoạn này:

Một trong những thuộc tính hữu ích nhất của biểu thức là được gọi bởi tính minh bạch tham chiếu Quine. Về bản chất, điều này có nghĩa là nếu chúng ta muốn tìm giá trị của biểu thức có chứa biểu thức con, điều duy nhất chúng ta cần biết về biểu thức con là giá trị của biểu thức. Bất kỳ tính năng nào khác của biểu thức phụ, chẳng hạn như cấu trúc bên trong của nó, số lượng và tính chất của các thành phần của nó, thứ tự chúng được đánh giá hoặc màu mực mà chúng được viết, không liên quan đến giá trị của chính biểu hiện.

Việc sử dụng "về bản chất" cho thấy Strachey đang diễn giải nó để giải thích nó bằng những thuật ngữ đơn giản. Các lập trình viên chức năng dường như hiểu đoạn này theo cách riêng của họ. Có 9 sự xuất hiện khác của "tính minh bạch tham chiếu" trong bài báo, nhưng dường như họ không bận tâm về bất kỳ vấn đề nào khác. Trên thực tế, toàn bộ bài viết của Strachey được dành để giải thích ý nghĩa của các ngôn ngữ lập trình mệnh lệnh . Nhưng, ngày nay, các lập trình viên chức năng tuyên bố rằng các ngôn ngữ lập trình mệnh lệnh không minh bạch về mặt tham chiếu. Strachey sẽ trở lại trong mộ của mình.

Chúng tôi có thể cứu vãn tình hình. Chúng tôi đã nói rằng ngôn ngữ tự nhiên là "lộn xộn, hoặc ít nhất là phức tạp" bởi vì nó được tạo ra để thuận tiện cho việc sử dụng thực tế. Ngôn ngữ lập trình là cùng một cách. Chúng "lộn xộn, hoặc ít nhất là phức tạp" bởi vì chúng được tạo ra để thuận tiện cho việc sử dụng thực tế. Điều đó không có nghĩa là họ cần nhầm lẫn chúng tôi. Họ chỉ cần được hiểu đúng cách, sử dụng một ngôn ngữ meta được minh bạch tham chiếu để chúng ta có sự rõ ràng về ý nghĩa. Trong bài báo tôi đã trích dẫn, Strachey thực hiện chính xác điều đó. Ông giải thích ý nghĩa của các ngôn ngữ lập trình mệnh lệnh bằng cách chia chúng thành các khái niệm cơ bản, không bao giờ mất đi sự rõ ràng ở bất cứ đâu. Một phần quan trọng trong phân tích của ông là chỉ ra rằng các biểu thức trong ngôn ngữ lập trình có hai loại "giá trị",giá trị r . Trước bài báo của Strachey, điều này không được hiểu và sự nhầm lẫn ngự trị tối cao. Ngày nay, định nghĩa của C đề cập đến nó thường xuyên và mọi lập trình viên C đều hiểu sự khác biệt. (Việc các lập trình viên trong các ngôn ngữ khác có hiểu nó tốt như nhau hay không là điều khó nói.)

Cả Quine và Strachey đều quan tâm đến ý nghĩa của các cấu trúc ngôn ngữ liên quan đến một số hình thức phụ thuộc vào ngữ cảnh. Ví dụ, ví dụ của chúng tôi "Edinburgh là thủ đô của Scotland từ năm 1999" biểu thị thực tế rằng "thủ đô của Scotland" phụ thuộc vào thời gian mà nó đang được xem xét. Sự phụ thuộc vào bối cảnh như vậy là một thực tế, cả trong ngôn ngữ tự nhiên và ngôn ngữ lập trình. Ngay cả trong lập trình chức năng, các biến tự do và ràng buộc phải được giải thích liên quan đến bối cảnh mà chúng xuất hiện. Sự phụ thuộc bối cảnh của bất kỳ loại nào ngăn chặn tính minh bạch tham chiếu theo cách này hay cách khác. Nếu bạn cố gắng hiểu ý nghĩa của các thuật ngữ mà không quan tâm đến bối cảnh mà chúng phụ thuộc, bạn sẽ lại bị nhầm lẫn. Quine quan tâm đến ý nghĩa của logic phương thức. Ông giữ điều đólogic phương thức bị mờ đục về mặt tham chiếu và nó cần được làm sạch bằng cách dịch nó thành một khung trong suốt tham chiếu (ví dụ, bằng cách coi sự cần thiết là khả năng chứng minh). Ông đã mất phần lớn cuộc tranh luận này. Các nhà logic học và các nhà triết học cũng nhận thấy ngữ nghĩa thế giới có thể của Kripke là hoàn toàn phù hợp. Tình hình tương tự cũng ngự trị với lập trình mệnh lệnh. Sự phụ thuộc vào nhà nước được giải thích bởi Strachey và sự phụ thuộc vào cửa hàng được giải thích bởi Reynold (theo cách tương tự như ngữ nghĩa thế giới có thể của Kripke) là hoàn toàn phù hợp. Các lập trình viên chức năng không biết nhiều về nghiên cứu này. Ý tưởng của họ về tính minh bạch tham chiếu sẽ được thực hiện với một hạt muối lớn.

[Ghi chú bổ sung: Các ví dụ trên minh họa rằng một cụm từ đơn giản như "thủ đô của Scotland" có nhiều cấp độ ý nghĩa. Ở một cấp độ, chúng ta có thể nói về thủ đô tại thời điểm hiện tại. Ở một cấp độ khác, chúng ta có thể nói về tất cả các thủ đô có thể mà Scotland có thể đã có trong suốt thời gian. Chúng ta có thể "phóng to" một bối cảnh cụ thể và "thu nhỏ" để mở rộng tất cả các bối cảnh khá dễ dàng trong thực tế thông thường. Hiệu quả của ngôn ngữ tự nhiên sử dụng khả năng của chúng tôi để làm như vậy. Các ngôn ngữ lập trình mệnh lệnh rất hiệu quả theo cùng một cách. Chúng ta có thể sử dụng một biến x ở phía bên phải của một bài tập ( giá trị r ) để nói về giá trị của nó trong một trạng thái cụ thể. Hoặc, chúng ta có thể nói về giá trị l của nómà kéo dài tất cả các tiểu bang. Mọi người hiếm khi bối rối bởi những điều như vậy. Tuy nhiên, họ có thể hoặc không thể giải thích chính xác tất cả các lớp ý nghĩa vốn có trong các cấu trúc ngôn ngữ. Tất cả các lớp ý nghĩa như vậy không nhất thiết là 'hiển nhiên' và vấn đề khoa học là nghiên cứu chúng đúng cách. Tuy nhiên, sự vô cảm của những người bình thường để giải thích những ý nghĩa phân lớp như vậy không có nghĩa là họ bối rối về chúng.]

Một "phần tái bút" riêng biệt dưới đây liên quan đến cuộc thảo luận này với các mối quan tâm của lập trình chức năng và mệnh lệnh .


10
Cảm ơn, nhưng tôi không cho rằng có một khái niệm mở rộng 'rõ ràng' về sự bình đẳng. Khi tôi nói "thủ đô của Scotland" đề cập đến thành phố Edinburgh, bạn đã không nghĩ hai lần về nó. Nhưng khi tôi bắt đầu nói về "từ năm 1999", bạn đột nhiên nhận ra rằng có thời gian liên quan. Vì vậy, khái niệm mở rộng về sự bình đẳng có thể khá tinh tế và nó được chính thức hóa bởi các nhà nghiên cứu ngôn ngữ lập trình. Những người muốn có một sự hiểu biết hoàn hảo về sự bình đẳng mở rộng cần phải tìm hiểu những thành quả của nghiên cứu đó. Nó có thể không hoàn toàn là "rõ ràng".
Uday Reddy

5
Tuyệt diệu! Một sự giải thoát đáng hoan nghênh cho những quan niệm sai lầm phổ biến về RT, ví dụ, buộc nó vào các chức năng . Hoặc xác định thông qua việc thay thế một biểu thức bằng giá trị của nó (như trên Wikipedia) - thật kỳ lạ vì các biểu thức và giá trị là các loại khác nhau. Có lẽ một nơi mà mọi người sai lầm khi xem xét RT-ness của các ngôn ngữ mệnh lệnh là giả định rằng những "giá trị" này là những thứ đơn giản như số chứ không phải là những thứ phức tạp hơn như chức năng từ một cửa hàng.
Conal

13
@sclv Về tác động rộng lớn hơn của triết học phân tích đối với Khoa học máy tính, tôi nên nói rằng Khoa học máy tính, như chúng ta biết, được thành lập bởi Godel, Church, Kleene và Turing. Những người này là những người logic và họ rất thành thạo cả hai khía cạnh toán học và triết học của logic, đặc biệt là các truyền thống của Peano, Frege, Russell, Whitehead, Carnap và Quine. Những người tiên phong đầu tiên của Khoa học Máy tính hiện đại đã biết các kết nối. Nhưng sự phát triển nhanh chóng của Khoa học Máy tính đã cắt đứt chúng. Chúng ta cần lấy lại cho họ.
Uday Reddy

5
@sclv Logic theo truyền thống được hiểu là khoa học về hậu quả . Nhưng tôi nghĩ nó rộng hơn. Đó là khoa học về thông tin . Quine, tôi xem như là người đầu tiên đưa ra cái nhìn rộng hơn. "Từ và đối tượng" là một phân tích về nội dung thông tin của các tuyên bố ngôn ngữ tự nhiên. Tuy nhiên, cả các nhà triết học và các nhà toán học đều không quan tâm tích cực đến các tính toán , điều này khá khó hiểu, do cách tính toán trung tâm đã được áp dụng cho nền văn minh và khoa học từ thời xa xưa. Chúng ta cần tìm cách khiến họ quan tâm.
Uday Reddy

3
@Conal: Tôi đã thêm một câu trả lời mới khuếch đại quan điểm của bạn. Nó có thể sẽ ở dưới cùng của trang.
Uday Reddy

134

Độ trong suốt tham chiếu, một thuật ngữ thường được sử dụng trong lập trình chức năng, có nghĩa là với một hàm và giá trị đầu vào, bạn sẽ luôn nhận được cùng một đầu ra. Đó là để nói rằng không có trạng thái bên ngoài được sử dụng trong chức năng.

Dưới đây là một ví dụ về chức năng minh bạch tham chiếu:

int plusOne(int x)
{
  return x+1;
}

Với hàm minh bạch tham chiếu, được cung cấp đầu vào và hàm, bạn có thể thay thế nó bằng một giá trị thay vì gọi hàm. Vì vậy, thay vì gọi plusOne với tham số là 5, chúng ta chỉ có thể thay thế bằng 6.

Một ví dụ điển hình khác là toán học nói chung. Trong toán học đã cho một hàm và một giá trị đầu vào, nó sẽ luôn ánh xạ tới cùng một giá trị đầu ra. f (x) = x + 1. Do đó, các hàm trong toán học được minh bạch tham chiếu.

Khái niệm này rất quan trọng đối với các nhà nghiên cứu bởi vì nó có nghĩa là khi bạn có một chức năng minh bạch tham chiếu, nó tự cho vay để tự động song song hóa và bộ nhớ đệm dễ dàng.

Độ trong suốt tham chiếu được sử dụng luôn trong các ngôn ngữ chức năng như Haskell.

-

Ngược lại có khái niệm về độ mờ đục tham chiếu. Điều này có nghĩa ngược lại. Gọi hàm có thể không luôn luôn tạo ra cùng một đầu ra.

//global G
int G = 10;

int plusG(int x)
{//G can be modified externally returning different values.
  return x + G;
}

Một ví dụ khác, là một hàm thành viên trong ngôn ngữ lập trình hướng đối tượng. Các hàm thành viên thường hoạt động trên các biến thành viên của nó và do đó sẽ mờ đục tham chiếu. Chức năng thành viên tất nhiên có thể được tham chiếu minh bạch.

Một ví dụ khác là một chức năng đọc từ tệp văn bản và in kết quả đầu ra. Tệp văn bản bên ngoài này có thể thay đổi bất cứ lúc nào vì vậy chức năng sẽ bị mờ đục.


1
Chỉ cần ngẩng cao đầu, có thể có một đối tượng trong suốt tham chiếu đầy đủ, với các hàm thành viên trong suốt tham chiếu. Xem okmij.org/ftp/Scheme/oop-in-fp.txt
Jonathan Arkell

1
Và đây là đoạn mã đang được nói đến trong bài viết đó: okmij.org/ftp/Scheme/pure-oo-system.scm
Jonathan Arkell

Trong trường hợp của một lớp trong suốt tham chiếu đầy đủ, có lẽ bạn sẽ có tất cả các hàm thành viên tĩnh.
Brian R. Bondy

13
Những gì bạn đang nói ở đây không phải là tính minh bạch tham chiếu, mặc dù nó thường được gọi là như vậy. Xem hai câu trả lời của Uday và các ý kiến ​​về chúng. Cụ thể, những gì bạn gọi là "đầu ra" không phải là ký hiệu. Nếu bạn thay thế "plusG 3" bằng bất kỳ biểu thức nào khác có cùng giá trị / ký hiệu, bạn thực sự sẽ có được một chương trình có cùng ý nghĩa, do đó RT không có ngôn ngữ bắt buộc. Biểu thức "3 + 10" hoặc "13" không có cùng nghĩa với "plusG 3", bởi vì ý nghĩa trong các ngôn ngữ mệnh lệnh là một chức năng của "cửa hàng" (trạng thái).
Conal

1
Tôi vừa đọc một bài viết về tác dụng phụ và thay đổi trạng thái và có một trực giác rằng nó có liên quan đến RT. Bạn có thể vui lòng thêm một ghi chú về nó?
Gaurav

91

Hàm trong suốt tham chiếu là một hàm chỉ phụ thuộc vào đầu vào của nó.


4
Đó là lý do tại sao nó khó trong lập trình OO vì các đối tượng có trạng thái.
Kris

5
Vì vậy, có đúng không khi nói "minh bạch tham chiếu" giống hệt với "tính xác định" khi mô tả các hàm? Nếu không, sự khác biệt giữa hai điều khoản là gì?
mwolfe02

1
Điều này cũng nghe giống như một định nghĩa của một chức năng "thuần túy".
Evgeny A.

75

[Đây là một phần tái bút cho câu trả lời của tôi từ ngày 25 tháng 3, trong nỗ lực đưa cuộc thảo luận đến gần hơn với các mối quan tâm của lập trình chức năng / mệnh lệnh.]

Ý tưởng về tính minh bạch tham chiếu của các lập trình viên chức năng dường như khác với khái niệm tiêu chuẩn theo ba cách:

  • Trong khi các nhà triết học / logic sử dụng các thuật ngữ như "tham chiếu", "biểu thị", "chỉ định" và " bedeutung " (thuật ngữ tiếng Đức của Frege), các lập trình viên chức năng sử dụng thuật ngữ "giá trị". (Đây không hoàn toàn là việc họ làm. Tôi nhận thấy rằng Landin, Strachey và con cháu của họ cũng sử dụng thuật ngữ "giá trị" để nói về tham chiếu / ký hiệu. Nó có thể chỉ là một cách đơn giản về thuật ngữ mà Landin và Strachey đã giới thiệu, nhưng nó dường như tạo ra một sự khác biệt lớn khi được sử dụng một cách ngây thơ.)

  • Các lập trình viên chức năng dường như tin rằng những "giá trị" này tồn tại trong ngôn ngữ lập trình chứ không phải bên ngoài. Khi làm điều này, họ khác với cả các nhà triết học và các nhà ngữ nghĩa ngôn ngữ lập trình.

  • Họ dường như tin rằng những "giá trị" này được cho là có được bằng cách đánh giá.

Ví dụ, bài viết Wikipedia về tính minh bạch tham chiếu cho biết, sáng nay:

Một biểu thức được cho là minh bạch tham chiếu nếu nó có thể được thay thế bằng giá trị của nó mà không thay đổi hành vi của một chương trình (nói cách khác, mang lại một chương trình có cùng hiệu ứng và đầu ra trên cùng một đầu vào).

Điều này hoàn toàn trái ngược với những gì các nhà triết học / logic nói. Họ nói rằng một bối cảnh là tham chiếu hoặc minh bạch tham chiếu nếu một biểu thức trong ngữ cảnh đó có thể được thay thế bằng một biểu thức khác đề cập đến cùng một điều (một biểu thức cốt lõi ). Những triết gia / nhà logic học này là ai? Họ bao gồm Frege , Russell , Whitehead , Carnap , Quine , Nhà thờvà vô số người khác. Mỗi người trong số họ là một nhân vật cao chót vót. Sức mạnh trí tuệ kết hợp của các nhà logic học này là ít nói nhất. Tất cả đều nhất trí ở vị trí mà người giới thiệu / ký hiệu tồn tại bên ngoài ngôn ngữ chính thức và các biểu thức trong ngôn ngữ chỉ có thể nói về họ. Vì vậy, tất cả những gì người ta có thể làm trong ngôn ngữ là thay thế một biểu thức bằng một biểu thức khác đề cập đến cùng một thực thể. Bản thân các tham chiếu / ký hiệu không tồn tại trong ngôn ngữ. Tại sao các lập trình viên chức năng đi chệch khỏi truyền thống được thiết lập tốt này?

Người ta có thể cho rằng các nhà ngữ nghĩa học ngôn ngữ lập trình có thể đã đánh lừa họ. Nhưng họ đã không làm thế.

Landin :

(a) mỗi biểu thức có cấu trúc biểu thức phụ lồng nhau, (b) mỗi biểu thức phụ biểu thị một cái gì đó (thường là một số, giá trị thật hoặc hàm số) , (c) biểu thức biểu thị, nghĩa là "giá trị" của nó các giá trị của biểu thức con của nó, không phải trên các thuộc tính khác của chúng. [Đã nhấn mạnh]

Stoy :

Điều duy nhất quan trọng về một biểu thức là giá trị của nó và bất kỳ biểu thức con nào cũng có thể được thay thế bằng bất kỳ giá trị bằng nào khác [Nhấn mạnh thêm]. Hơn nữa, giá trị của một biểu thức là, trong các giới hạn nhất định, giống nhau bất cứ khi nào nó xuất hiện ".

Chim và Wadler :

giá trị của một biểu thức chỉ phụ thuộc vào các giá trị của các biểu thức cấu thành của nó (nếu có) và các biểu thức con này có thể được thay thế tự do bởi các biểu thức khác có cùng giá trị [Nhấn mạnh thêm].

Vì vậy, khi nhìn lại, những nỗ lực của Landin và Strachey để đơn giản hóa thuật ngữ bằng cách thay thế "tham chiếu" / "ký hiệu" bằng "giá trị" có thể đã gây hại. Ngay khi nghe về một "giá trị", sẽ có một sự cám dỗ khi nghĩ về một quy trình đánh giá dẫn đến nó. Thật hấp dẫn không kém khi nghĩ về bất cứ điều gì mà đánh giá tạo ra là "giá trị", mặc dù có thể khá rõ ràng rằng đó không phải là biểu thị. Đó là những gì tôi thu thập được đã xảy ra với khái niệm "minh bạch tham chiếu" trong mắt các lập trình viên chức năng. Nhưng "giá trị" được nói bởi các nhà ngữ nghĩa học ban đầu không phải là kết quả của một đánh giá hoặc đầu ra của một chức năng hoặc bất kỳ điều gì như vậy. Đó là ký hiệu của thuật ngữ.

Một khi chúng ta hiểu cái gọi là "giá trị" của một biểu thức ("tham chiếu" hoặc "biểu thị" trong diễn ngôn của các nhà triết học cổ điển) như một đối tượng toán học / khái niệm phức tạp, tất cả các loại khả năng sẽ mở ra.

  • Strachey diễn giải các biến trong các ngôn ngữ lập trình mệnh lệnh là giá trị L , như được đề cập trong câu trả lời ngày 25 tháng 3 của tôi, đây là một đối tượng khái niệm tinh vi không có biểu diễn trực tiếp trong cú pháp của ngôn ngữ lập trình.
  • Ông cũng diễn giải các lệnh bằng các ngôn ngữ như các hàm trạng thái, một thể hiện khác của một đối tượng toán học phức tạp không phải là "giá trị" trong cú pháp.
  • Ngay cả một lệnh gọi hàm tác dụng phụ trong C cũng có một "giá trị" được xác định rõ là một biến áp trạng thái ánh xạ các trạng thái thành các cặp trạng thái và giá trị (cái gọi là "đơn nguyên" trong thuật ngữ của các lập trình viên chức năng).

Sự miễn cưỡng của các lập trình viên chức năng gọi các ngôn ngữ đó là "minh bạch tham chiếu" chỉ ngụ ý rằng họ miễn cưỡng thừa nhận các đối tượng toán học / khái niệm phức tạp như vậy là "giá trị". Mặt khác, họ dường như hoàn toàn sẵn sàng gọi một biến áp trạng thái là "giá trị" khi nó được đặt theo cú pháp yêu thích của riêng họ và mặc quần áo với một từ buzz như "monad". Tôi phải nói rằng họ đang hoàn toàn không nhất quán, ngay cả khi chúng tôi cấp cho họ rằng ý tưởng "minh bạch tham chiếu" của họ có sự gắn kết.

Một chút lịch sử có thể làm sáng tỏ về cách những nhầm lẫn này ra đời. Giai đoạn từ 1962 đến 1967 là một giai đoạn rất nặng nề đối với Christopher Strachey. Trong khoảng thời gian 1962-65, ông đã làm một công việc bán thời gian với tư cách là trợ lý nghiên cứu với Maurice Wilkes để thiết kế và thực hiện ngôn ngữ lập trình được gọi là CPL. Đây là một ngôn ngữ lập trình bắt buộc nhưng cũng có nghĩa là có khả năng ngôn ngữ lập trình chức năng mạnh mẽ. Landin, một nhân viên của Strachey trong công ty tư vấn của mình, có ảnh hưởng rất lớn đến quan điểm của Strachey về ngôn ngữ lập trình. Trong bài viết nổi bật năm 1969 " 700 ngôn ngữ lập trình tiếp theo ", Landin không ngừng quảng bá các ngôn ngữ lập trình chức năng (gọi chúng là biểu thịngôn ngữ) và mô tả các ngôn ngữ lập trình mệnh lệnh là "phản đề" của chúng. Trong cuộc thảo luận tiếp theo, chúng tôi thấy Strachey đặt ra nghi ngờ về vị thế mạnh mẽ của Landin.

... DLs tạo thành một tập hợp con của tất cả các ngôn ngữ. Chúng là một tập hợp con thú vị, nhưng là một tập hợp bất tiện khi sử dụng trừ khi bạn đã quen với nó. Chúng tôi cần chúng bởi vì hiện tại chúng tôi không biết cách xây dựng bằng chứng với các ngôn ngữ bao gồm mệnh lệnh và bước nhảy. [Đã nhấn mạnh]

Năm 1965, Strachey đảm nhận vị trí Độc giả tại Oxford và dường như đã làm việc chủ yếu toàn thời gian để phát triển một lý thuyết về mệnh lệnh và bước nhảy. Đến năm 1967, anh đã sẵn sàng với một lý thuyết, mà anh đã dạy trong khóa học về " Khái niệm cơ bản trong ngôn ngữ lập trình " tại một trường học hè ở Copenhagen. Các ghi chú bài giảng được cho là đã được xuất bản nhưng "thật không may, vì chỉnh sửa mở rộng, các thủ tục tố tụng không bao giờ được thực hiện, giống như nhiều công việc của Strachey tại Oxford, tuy nhiên, bài báo có lưu hành tư nhân có ảnh hưởng." ( Martin Campbell-Kelly )

Khó khăn trong việc có được các tác phẩm của Strachey có thể đã dẫn đến sự nhầm lẫn được truyền bá, với những người dựa vào các nguồn thứ cấp và tin đồn. Nhưng, bây giờ " Các khái niệm cơ bản " đã có sẵn trên web, không cần phải dùng đến công việc đoán. Chúng ta nên đọc nó và tạo nên suy nghĩ của riêng mình về ý nghĩa của Strachey. Đặc biệt:

  • Trong phần 3.2, anh ta đề cập đến "các biểu thức" trong đó anh ta nói về "tính minh bạch tham chiếu giá trị R".
  • Phần 3.3 của anh đề cập đến "các lệnh" trong đó anh nói về "tính minh bạch tham chiếu giá trị L".
  • Trong phần 3.4.5, ông nói về "các hàm và thói quen" và tuyên bố rằng "mọi sự rời khỏi độ trong suốt của tham chiếu giá trị R trong ngữ cảnh giá trị R nên được loại bỏ bằng cách phân tách biểu thức thành một số lệnh và các biểu thức đơn giản hơn, hoặc, nếu Điều này hóa ra là khó khăn, chủ đề của một bình luận. "

Bất kỳ cuộc nói chuyện nào về "tính minh bạch tham chiếu" mà không hiểu sự khác biệt giữa giá trị L, giá trị R và các đối tượng phức tạp khác tạo ra vũ trụ khái niệm của lập trình viên mệnh lệnh đều bị nhầm lẫn về cơ bản.


10
Tôi nghĩ rằng đáng để nhấn mạnh rằng việc nhầm lẫn hai khái niệm "giá trị" (đánh giá và biểu thị) này đã đánh lừa các lập trình viên chức năng trong việc chỉ trích các ngôn ngữ mệnh lệnh , trong đó khoảng cách giữa các khái niệm là lớn.
Conal

8
tức là, khái niệm đánh giá dẫn đến kết luận rằng các ngôn ngữ mệnh lệnh không phải là RT, trong khi khái niệm ký hiệu thì không.
Conal

12
Dường như với tôi rằng một khi bạn thực sự đóng đinh hoàn toàn ngữ nghĩa học của ngôn ngữ, nó không thể giúp được nhưng phải minh bạch về mặt tham chiếu. Vì vậy, điều này có vẻ tương đương với việc nói rằng thuật ngữ này không hữu ích đối với các ngôn ngữ lập trình.
Tom Crockett

20
Vì vậy, có vẻ như mọi người đang có thói quen sử dụng một thuật ngữ để chỉ một thứ gì đó khác biệt về mặt vật chất so với những người khác có nghĩa là khi họ sử dụng thuật ngữ đó trong quá khứ. Tôi nói: Chào mừng bạn đến với ngôn ngữ tiếng Anh.
Daniel Pratt

17
@DanielPratt: Nếu tự do tác dụng phụ là những gì các lập trình viên chức năng muốn nói, thì tại sao họ gọi nó là "minh bạch tham chiếu"? Họ chỉ có thể gọi nó là "tự do tác dụng phụ", đó là một ý tưởng hoàn toàn rõ ràng. Không ai cần phải hỏi về stackexchange "tự do tác dụng phụ" nghĩa là gì. Đâu là nhu cầu để thuần túy các thuật ngữ cổ điển hoành tráng mà dường như không ai hiểu được?
Uday Reddy

23

Một biểu thức được minh bạch tham chiếu nếu nó có thể được thay thế bằng giá trị của nó, mà không thay đổi thuật toán, mang lại một thuật toán có cùng hiệu ứng và đầu ra trên cùng một đầu vào.


18

Hàm minh bạch tham chiếu là hàm hoạt động như hàm toán học; với cùng một đầu vào, nó sẽ luôn tạo ra các đầu ra giống nhau. Nó ngụ ý rằng trạng thái được truyền vào không được sửa đổi và hàm không có trạng thái của chính nó.


10

Đối với những người cần một lời giải thích ngắn gọn, tôi sẽ mạo hiểm một (nhưng đọc phần tiết lộ dưới đây).

Tính minh bạch tham chiếu trong ngôn ngữ lập trình thúc đẩy lý luận bằng phương trình - tính minh bạch tham chiếu càng nhiều thì càng dễ thực hiện lý luận tương đương. Ví dụ: với định nghĩa hàm (giả),

fx = x + x,

sự dễ dàng mà bạn có thể (một cách an toàn) thay thế f (foo) bằng foo + foo trong phạm vi định nghĩa này, mà không có quá nhiều ràng buộc về nơi bạn có thể thực hiện việc giảm này, là một dấu hiệu tốt về mức độ minh bạch của ngôn ngữ lập trình tham chiếu của bạn có.

Ví dụ: nếu foo là x ++ theo nghĩa lập trình C thì bạn không thể thực hiện việc giảm này một cách an toàn (nghĩa là, nếu bạn thực hiện việc giảm này, bạn sẽ không kết thúc với cùng một chương trình mà bạn đã bắt đầu).

Trong các ngôn ngữ lập trình thực tế, bạn sẽ không thấy tính minh bạch tham chiếu hoàn hảo nhưng các lập trình viên chức năng quan tâm đến nó nhiều hơn hầu hết (cf Haskell, trong đó mục tiêu cốt lõi).

(Tiết lộ đầy đủ: Tôi là một lập trình viên chức năng vì vậy theo câu trả lời hàng đầu, bạn nên đưa ra lời giải thích này với một hạt muối.)


3
Tôi không có vấn đề với các ngôn ngữ tạo điều kiện cho lý luận bình đẳng. Nhưng tôi sẽ tranh luận rằng nó có liên quan gì đến "tính minh bạch tham chiếu" như được định nghĩa kinh điển. Thứ hai, là một lập trình viên thực tế, tôi nghĩ lý luận tương đương được đánh giá cao. Lý do quan trọng trong thực tế phải làm với các điều kiện trước, hậu điều kiện, bất biến và trừu tượng hóa dữ liệu. Đối với những người dựa vào các kỹ thuật lý luận như vậy, tác dụng phụ dường như không quan trọng lắm. Vì vậy, trong khi tôi đồng ý với bạn rằng các tác dụng phụ trong biểu hiện là một ý tưởng tồi, dường như chúng không đại diện cho một lập luận giết người.
Uday Reddy

1
@UdayReddy Chỉ vì các lập trình viên chức năng đã chọn một phương pháp đặc biệt để quay số tính minh bạch tham chiếu trong chương trình của họ (loại bỏ tác dụng phụ và phát triển một đại số chương trình tinh vi và mạnh mẽ), hoặc có một số học viên có thể không hiểu về tính minh bạch tham chiếu cũng như họ nghĩ rằng họ làm, không có nghĩa là các ngôn ngữ lập trình chức năng không làm tăng tính minh bạch tham chiếu hoặc các nhà lập trình ngôn ngữ chức năng và các nhà văn biên dịch không khai thác sự gia tăng này trong khả năng chuyển đổi chính thức đến nhiều kết thúc tốt.
chrisdornan

2
Chris: Uday chỉ ra rằng Strachey đã loại bỏ vấn đề về độ mờ tham chiếu trong ngữ nghĩa ngôn ngữ lập trình, đặc biệt đối với các ngôn ngữ bắt buộc. Vì vậy, các lập trình viên chức năng không thể "quay số minh bạch tham chiếu trong các chương trình của họ". Một ví dụ cụ thể, Haskell IO không giúp gì được với RT chính xác vì không cần trợ giúp RT.
Conal

2
@chrisdornan: Xin lỗi vì nhận xét đầu tiên của tôi ở trên. Bản thân tôi đã gặp khó khăn trong việc tìm ra những gì tôi đã cố gắng nói trong hai câu đầu tiên :-( Nhưng, đây là một lời giải thích. Hãy xem xét một phép tính phân tầng hai cấp hoặc đa cấp. Mỗi nhà điều hành dàn đều tham chiếu mờ. Tuy nhiên, mỗi toán tử mờ tham chiếu thiết lập ranh giới cho lý luận phương trình. Nhưng bạn vẫn có lý luận tương đương trong các ranh giới đó.
Uday Reddy

1
@chrisdomain: Hơn nữa, rất ít người muốn trở thành những người theo chủ nghĩa minh bạch tham chiếu để trục xuất các nhà khai thác dàn dựng như vậy. Những toán tử này cực kỳ hữu ích. Lập trình mà không có chúng bằng cách thực hiện thủ công sẽ rất tẻ nhạt, dễ bị lỗi và xấu. Và, thực hiện dàn dựng thủ công sẽ không mua cho bạn bất kỳ lý do công bằng hơn so với những gì bạn có trước đó. Vì vậy, việc cấm các thiết bị lập trình tốt trong việc theo đuổi lý luận thuần túy sẽ giống như cắt mũi để làm cay khuôn mặt của bạn.
Uday Reddy

8

Nếu bạn quan tâm đến từ nguyên (nghĩa là tại sao khái niệm này có tên cụ thể này), hãy xem bài viết trên blog của tôi về chủ đề này. Thuật ngữ này xuất phát từ nhà triết học / nhà logic học Quine.


4
  1. Denotational-semantics dựa trên mô hình hóa các ngôn ngữ bằng cách xây dựng các miền tạo thành các giá trị có thể biểu thị được .
  2. Các lập trình viên chức năng sử dụng giá trị thuật ngữ để mô tả sự hội tụ của một tính toán dựa trên các quy tắc viết lại của ngôn ngữ tức là. ngữ nghĩa hoạt động của nó.

Trong 1 có một sự rõ ràng của hai ngôn ngữ trong câu hỏi:

  • một trong những mô hình, ngôn ngữ đối tượng
  • ngôn ngữ của người mẫu, ngôn ngữ meta

Trong 2, nhờ sự gần gũi của vật thể và kim loại, chúng có thể bị nhầm lẫn.

Là một người thực hiện ngôn ngữ, tôi thấy rằng tôi cần liên tục ghi nhớ sự khác biệt này.

Vì vậy, giáo sư Reddy có thể diễn giải bạn như vậy :-)

Trong bối cảnh của lập trình chức năng và ngữ nghĩa, thuật ngữ Minh bạch tham chiếu không tham chiếu minh bạch.


1
Ha ha. Cảm ơn đã giải thích. Vấn đề cũng là các lập trình viên chức năng hành động như thể họ có một khái niệm chung về "tính minh bạch tham chiếu" có thể áp dụng cho tất cả các ngôn ngữ lập trình . Nhưng điều này phụ thuộc vào khái niệm "giá trị" của họ, có thể có hoặc không có ý nghĩa đối với các ngôn ngữ khác. Để yêu cầu một lý thuyết chung về "tính minh bạch tham chiếu", họ cần tạo ra một "giá trị" lý thuyết chung. Đó là mất tích cho đến nay.
Uday Reddy

4

Câu trả lời sau đây tôi hy vọng sẽ bổ sung và đủ điều kiện cho câu trả lời thứ 1 và thứ 3 gây tranh cãi.

Chúng ta hãy cho rằng một biểu thức biểu thị hoặc đề cập đến một số người giới thiệu. Tuy nhiên, một câu hỏi là liệu các tham chiếu này có thể được mã hóa một cách đồng hình như là một phần của chính các biểu thức hay không, gọi các biểu thức đó là 'giá trị'. Ví dụ, các giá trị số bằng chữ là một tập hợp con của tập hợp các biểu thức số học, các giá trị chân lý là tập con của tập hợp các biểu thức boolean, v.v. Ý tưởng là đánh giá một biểu thức cho giá trị của nó (nếu nó có một biểu thức). Vì vậy, từ 'giá trị' có thể đề cập đến một ký hiệu hoặc một yếu tố phân biệt của tập hợp các biểu thức. Nhưng nếu có một sự đẳng cấu (một mệnh đề) giữa người giới thiệu và giá trị chúng ta có thể nói chúng là cùng một thứ. (Điều này nói rằng, người ta phải cẩn thận để xác định các tham chiếu và đẳng cấu, như đã được chứng minh bởi lĩnh vực ngữ nghĩa học biểu thị.data Nat = Zero | Suc Nat không tương ứng như mong đợi với tập hợp các số tự nhiên.)

Hãy để chúng tôi viết E[·]cho một biểu thức có một lỗ, còn được gọi là "bối cảnh" trong một số phần tư. Hai ví dụ bối cảnh cho các biểu thức giống như C là [·]+1[·]++.

Chúng ta hãy viết [[·]]cho hàm có một biểu thức (không có lỗ) và cung cấp ý nghĩa của nó (tham chiếu, ký hiệu, v.v.) trong một số vũ trụ cung cấp ý nghĩa. (Tôi đang mượn ký hiệu từ lĩnh vực ngữ nghĩa học.)

Chúng ta hãy điều chỉnh định nghĩa của Quine một cách chính thức như sau: một bối cảnh E[·] được minh bạch tham chiếu với hai biểu thức E1E2(không có lỗ hổng nào) sao cho [[E1]] = [[E2]](nghĩa là các biểu thức biểu thị / tham chiếu đến cùng một tham chiếu) thì đó là trường hợp [[E[E1]]] = [[E[E2]]](nghĩa là điền vào -trong lỗ với một trong hai E1hoặc E2kết quả trong các biểu thức cũng biểu thị cùng một tham chiếu).

Nguyên tắc thay thế bình đẳng cho equals Leibniz thường thể hiện dưới dạng 'nếu E1 = E2sau đó E[E1] = E[E2]', mà nói rằng E[·]là một hàm. Hàm (hoặc đối với vấn đề đó là chương trình tính toán hàm) là ánh xạ từ nguồn tới đích để có nhiều nhất một phần tử đích cho mỗi phần tử nguồn. Chức năng không xác định là misnomers, họ là một trong hai quan hệ, chức năng cung cấp bộ, vv Nếu trong quy tắc Leibniz sự bình đẳng =là denotational thì đôi dấu ngoặc chỉ đơn giản là đưa cho các cấp và elided. Vì vậy, một bối cảnh minh bạch tham chiếu là một chức năng. Và quy tắc của Leibniz là thành phần chính của lý luận tương đương, vì vậy lý luận phương trình chắc chắn có liên quan đến tính minh bạch tham chiếu.

Mặc dù [[·]]là một hàm từ biểu thức đến ký hiệu, nó có thể là hàm từ biểu thức đến 'giá trị' được hiểu là tập con hạn chế của biểu thức và [[·]]có thể hiểu là đánh giá.

Bây giờ, nếu E1là một biểu thức và E2là một giá trị chúng ta có những gì tôi nghĩ có nghĩa là hầu hết mọi người khi xác định tính minh bạch tham chiếu về mặt biểu thức, giá trị và đánh giá. Nhưng như được minh họa bởi câu trả lời thứ 1 và thứ 3 trong trang này, đây là một định nghĩa không chính xác.

Vấn đề với các bối cảnh như [·]++không phải là tác dụng phụ, mà là giá trị của nó không được định nghĩa trong C về mặt đồng nghĩa với ý nghĩa của nó. Hàm không phải là giá trị (tốt, con trỏ tới hàm là) trong khi đó trong ngôn ngữ lập trình hàm. Landin, Strachey và những người tiên phong về ngữ nghĩa học phi nghĩa là khá thông minh trong việc sử dụng các thế giới chức năng để cung cấp ý nghĩa.

Đối với các ngôn ngữ giống như C bắt buộc, chúng ta có thể (đại khái) cung cấp ngữ nghĩa cho các biểu thức bằng cách sử dụng hàm [[·]] : Expression -> (State -> State x Value).

Valuelà một tập hợp con của Expression. Statechứa các cặp (định danh, giá trị). Hàm ngữ nghĩa nhận một biểu thức và cung cấp theo nghĩa của nó là một hàm từ trạng thái hiện tại đến cặp với trạng thái được cập nhật và một giá trị. Ví dụ, [[x]]là hàm từ trạng thái hiện tại đến cặp có thành phần đầu tiên là trạng thái hiện tại và thành phần thứ hai là giá trị của x. Ngược lại, [[x++]]là hàm từ trạng thái hiện tại đến cặp có thành phần đầu tiên là trạng thái trong đó giá trị của x được tăng lên và thành phần thứ hai có giá trị rất cao. Theo nghĩa này, bối cảnh [·]++được minh bạch tham chiếu nếu nó thỏa mãn định nghĩa được đưa ra ở trên.

Tôi nghĩ rằng các lập trình viên chức năng có quyền sử dụng tính minh bạch tham chiếu theo nghĩa họ phục hồi tự nhiên [[·]]như một hàm từ biểu thức đến giá trị. Các hàm là các giá trị hạng nhất và trạng thái cũng có thể là một giá trị, không phải là một biểu thị. Các đơn vị trạng thái là (một phần) một cơ chế sạch để chuyển (hoặc phân luồng) trạng thái.


Có lẽ câu trả lời "thứ nhất" và "thứ 3" lần lượt là câu trả lời "ngày 25 tháng 3" và "phần tái bút" của UdayReddy. Thông thường không phải là một cách tốt để tham khảo các câu trả lời trong SO. Không chỉ phiếu bầu và chấp nhận thay đổi theo thời gian mà còn có nhiều thứ tự lựa chọn.
philipxy

2

Lưu ý rằng khái niệm "ý nghĩa" này là một cái gì đó xảy ra trong tâm trí của người quan sát. Do đó, cùng một "tham chiếu" có thể có nghĩa là những điều khác nhau cho những người khác nhau. Vì vậy, ví dụ, chúng ta có một trang định hướng ở Edinburgh trong Wikipedia.

Một vấn đề liên quan có thể xuất hiện trong bối cảnh lập trình có thể là đa hình.

Và có lẽ chúng ta nên đặt tên cho trường hợp đặc biệt của đa hình (hoặc thậm chí là đúc) trong đó với mục đích của chúng ta, các trường hợp đa hình khác nhau là tương đương về mặt ngữ nghĩa (trái ngược với chỉ là tương tự. Ví dụ, số 1 - có thể được biểu diễn sử dụng một loại số nguyên, hoặc một loại phức tạp hoặc bất kỳ loại nào khác - có thể được xử lý đa hình).


0

Tôi thấy định nghĩa về tính minh bạch tham chiếu trong cuốn sách " Cấu trúc và triển khai các chương trình máy tính " (Sách hướng dẫn) hữu ích vì nó được bổ sung bởi một lời giải thích về cách thức minh bạch tham chiếu bị vi phạm bằng cách giới thiệu hoạt động chuyển nhượng . Kiểm tra các boong trượt sau tôi đã thực hiện về chủ đề này: https://www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-evaluation-and-violates-referential-transparency-as- giải thích trong sicp-the-wizard-book


0

Tính minh bạch tham chiếu có thể được chỉ định đơn giản là:

  • Một biểu thức luôn luôn đánh giá đến cùng một kết quả trong bất kỳ bối cảnh nào [1] ,
  • Một hàm, nếu được cung cấp cùng một tham số hai lần, phải tạo ra cùng một kết quả hai lần [2] .

Ví dụ, ngôn ngữ lập trình Haskell là ngôn ngữ chức năng thuần túy; có nghĩa là nó được minh bạch tham chiếu.

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.