";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
Phiên bản không trích dẫn: Hãy thử nó trên tiền mã hóa.
Phiên bản trích dẫn: Hãy thử nó trên tiền mã hóa.
Lưu ý rằng đầu ra trông giống như thế này
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
bởi vì mã được giải thích khai báo bằng cách khai báo (mỗi ;
kết thúc một khai báo) và hiển thị giá trị và loại của mỗi khai báo.
Lý lịch
Trong SML có một quine có dạng <code>"<code in quotes>"
:
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
và một trong mẫu "<code in quotes>"<code>
:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
Cả hai đều dựa vào thực tế là <code>
phần không chứa dấu ngoặc kép và do đó có thể được trích dẫn mà không cần phải thoát bất cứ điều gì, "
cần thiết để đưa ra quine được đưa ra bởi str(chr 34)
.
Họ cũng phụ thuộc rất nhiều vào định danh ngầm it
được sử dụng khi không có định danh rõ ràng nào được đưa ra trong một tuyên bố.
Trong quine đầu tiên str(chr 34);
liên kết it
với chuỗi chứa "
, fn x=>
bắt đầu một hàm ẩn danh lấy một đối số x
, sau đó nối x^it^x^it
và in chuỗi kết quả. Hàm ẩn danh này được áp dụng trực tiếp vào một chuỗi chứa mã chương trình, do đó, kết x^it^x^it
quả sẽ mang lại kết quả <code>"<code>"
.
Câu hỏi thứ hai bắt đầu chỉ với mã chương trình là chuỗi ";str(chr 34)^it;print(it^it)";
được ràng buộc it
. Sau đó str(chr 34)^it;
nối một trích dẫn vào đầu chuỗi và vì một lần nữa không có định danh rõ ràng nào được đưa ra, chuỗi kết quả "<code>
được ràng buộc it
. Cuối cùng print(it^it)
nối chuỗi với chính nó mang lại "<code>"<code>
sau đó được in.
Giải trình
Chỉnh sửa: Không còn cập nhật với phiên bản 108 byte, tuy nhiên người ta cũng có thể hiểu nó sau khi đọc giải thích này.
Câu hỏi an toàn trích dẫn kết hợp cả hai cách tiếp cận trên và chính nó là hình thức "<code>"<code>
. Đặt điều này một lần nữa trong các trích dẫn mang lại ""<code>"<code>"
, vì vậy chúng tôi nhận được một chuỗi rỗng và sau đó là một quine của hình thức khác.
Điều đó có nghĩa là chương trình được cung cấp nguồn riêng dưới dạng "<code>
định danh it
hoặc it
là chính xác "
và chúng ta được cung cấp nguồn riêng của mình <code>
dưới dạng đối số và do đó phải là một hàm xử lý một đối số như vậy.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
Để xác định trong trường hợp này chúng tôi, chúng tôi kiểm tra xem kích thước của it
lớn hơn 1. Nếu không thì it
là "
và chúng tôi đang trong trường hợp thứ hai, do đó else
lợi nhuận -part một chức năng ẩn danh fn x=>print(it^it^x^it^x^it)
mà sau đó được gọi là bởi vì sau đó nó theo nguồn như chuỗi . Lưu ý hàng đầu it^it^
cần thiết cho chuỗi trống khi bắt đầu chương trình.
Nếu size it
lớn hơn 1, chúng ta sẽ ở trong then
phần và chỉ thực hiện print(it^it)
, phải không? Không hoàn toàn, vì tôi đã bỏ qua việc nói với bạn rằng SML được gõ mạnh, điều đó có nghĩa là một điều kiện if <cond> then <exp_1> else <exp_2>
phải luôn có cùng loại, điều đó có nghĩa là các biểu thức <exp_1>
và <exp_2>
cần phải có cùng loại. Chúng ta đã biết loại else
phần: Một hàm ẩn danh nhận một chuỗi và sau đó các cuộc gọi print
có loại string -> <return type of print>
và print
có loại string -> unit
( unit
theo một cách nào đó tương tự như void
trong các ngôn ngữ khác), do đó, loại kết quả là một lần nữa string -> unit
.
Vì vậy, nếu then
phần chỉ print(it^it)
có loại unit
, chúng ta sẽ gặp lỗi không khớp loại. Vậy làm thế nào về fn _=>print(it^it)
? ( _
Là một ký tự đại diện cho một cuộc tranh cãi rằng không được sử dụng) chức năng ẩn danh này ngày của riêng mình đã loại 'a -> unit
nơi 'a
tượng trưng cho một loại tùy ý, vì vậy trong bối cảnh điều kiện của chúng tôi mà thực thi một string -> unit
loại hình này sẽ làm việc. (Biến loại 'a
được khởi tạo với loại string
.) Tuy nhiên, trong trường hợp này, chúng tôi sẽ không in bất cứ điều gì vì hàm ẩn danh không bao giờ được gọi! Hãy nhớ rằng, khi chúng ta đi vào then
phần -part, mã tổng thể là "<code>"<code>
, vì vậy <code>
phần-ước tính cho một hàm nhưng, vì không có gì xuất hiện sau nó, nên nó không được gọi.
Thay vào đó chúng tôi sử dụng một sequentialisation trong đó có các hình thức (<exp_1>; ...; <exp_n>)
nơi <exp_1>
để <exp_n-1>
có thể có các loại độc đoán và các loại <exp_n>
cung cấp các loại toàn bộ sequentialisation. Từ quan điểm chức năng của xem các giá trị của <exp_1>
để <exp_n-1>
chỉ đơn giản là loại bỏ, tuy nhiên SML cũng hỗ trợ cấu trúc bắt buộc để các biểu thức có thể có tác dụng phụ. Nói tóm lại, chúng tôi lấy (print(it^it);print)
làm then
-part, do đó in trước rồi trả về hàm print
có đúng loại.