val()=hd[(fn s=>let val$ =s^"\""^String.toString s^"\"]"val(189,%)=(size$,$)in print%end)"val()=hd[(fn s=>let val$ =s^\"\\\"\"^String.toString s^\"\\\")\"val(189,%)=(size$,$)in print%end)"]
Hãy thử trực tuyến!
Đối với MLton, các chương trình SML đầy đủ là các biểu thức được phân tách và kết thúc bằng ;
(ví dụ print"Hello";print"World";
) hoặc khai báo bằng var
và fun
từ khóa (ví dụ var _=print"Hello"var _=print"World"
) trong đó _
là một thẻ đại diện cũng có thể được thay thế bằng bất kỳ tên biến nào.
Tùy chọn đầu tiên là vô dụng đối với lập trình nguyên sơ bởi vì ;
bản thân nó là một chương trình hợp lệ (không có gì, nhưng cũng không có lỗi). Vấn đề với cách tiếp cận thứ hai là các khai báo như var _=print"Hello"
có thể được rút ngắn thành chỉ var _="Hello"
(hoặc thậm chí var _=print
) bởi vì khai báo có var
tác dụng miễn là phía bên phải là một biểu thức hoặc giá trị SML hợp lệ (SML là ngôn ngữ chức năng, vì vậy các hàm có thể dùng làm giá trị quá).
Tại thời điểm này, tôi đã sẵn sàng tuyên bố lập trình nguyên sơ trong SML là không thể, khi tình cờ tôi tình cờ tìm thấy mô hình khớp trong các tuyên bố val
. Nó chỉ ra rằng cú pháp khai báo không phải là , val <variable_name> = <expression>
nhưng val <pattern> = <expression>
trong đó một mẫu có thể bao gồm các tên biến, hằng và hàm tạo. Khi print
hàm có kiểu string -> unit
, chúng ta có thể sử dụng khớp mẫu trên unit
-value ()
để thực thi rằng hàm in thực sự được áp dụng cho chuỗi : val()=print"Hey"
. Với phương pháp này, loại bỏ một trong hai print
hoặc "Hey"
kết quả trong một Pattern and expression disagree
-error.
Với cách in nguyên sơ này trong tay, bước tiếp theo là viết một quine, trước khi cuối cùng một số bảo vệ tiết kiệm hơn cần được thêm vào. Trước đây tôi đã sử dụng một kỹ thuật quine SML dễ dàng (xem lịch sử sửa đổi ), nhưng Anders Kaseorg đã chỉ ra một cách tiếp cận khác có thể lưu một số byte trong trường hợp của anh ta. Nó sử dụng String.toString
hàm tích hợp để xử lý thoát chuỗi và có dạng chung <code>"<data>"
, trong đó "<data>"
là một chuỗi thoát code
trước đó:
val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"
Đây là một quine làm việc nhưng chưa nguyên sơ. Trước hết, Anders Kaseorg phát hiện ra rằng MLton chấp nhận một trích dẫn "
là mã mà không tạo ra lỗi, điều đó có nghĩa là chúng ta không thể có mã kết thúc bằng một trích dẫn như trên. Cách ngắn nhất để ngăn chặn điều này là bọc mọi thứ sau val()=
một cặp ngoặc đơn, tuy nhiên sau đó mã có thể được giảm xuống val()=()
. Cách ngắn nhất thứ hai tôi tìm thấy là sử dụng val()=hd[ ... ]
, đó là chúng tôi gói mọi thứ vào một danh sách và trả về phần tử đầu tiên của nó để làm cho trình kiểm tra kiểu hài lòng.
Để đảm bảo rằng không có phần nào của chuỗi dữ liệu có thể bị xóa mà không bị chú ý, kết hợp khớp mẫu trong val
-declarations lại có ích: Độ dài của chuỗi cuối cùng được in (và do đó độ dài chương trình) phải bằng 195, vì vậy chúng ta có thể viết let val t=... val 195=size t in print t end
trong phần fn
trừu tượng thay vì print(...)
. Loại bỏ một phần của chuỗi kết quả có độ dài nhỏ hơn 189, do đó gây ra Bind
ngoại lệ.
Vẫn còn một vấn đề: toàn bộ val 195=size t
kiểm tra có thể bị hủy bỏ. Chúng tôi có thể ngăn chặn điều này bằng cách mở rộng kiểm tra để khớp trên một tuple : val t=... val(216,u)=(n+size t,t)in print u end
, ví dụ như loại bỏ kết quả kiểm tra trong một biến không liên kết u
.
Nhìn chung, điều này mang lại giải pháp 195 byte sau đây:
val()=hd[(fn s=>let val t=s^"\""^String.toString s^"\")"val(195,u)=(size t,t)in print u end)"val()=hd[(fn s=>let val t=s^\"\\\"\"^String.toString s^\"\\\")\"val(195,u)=(size t,t)in print u end)"]
Áp dụng thủ thuật đánh gôn bằng cách sử dụng các tên biến toán tử như !
, $
và %
thay vì n
, t
và u
để tiết kiệm một số khoảng trắng (xem mẹo này ) dẫn đến phiên bản 182 byte cuối cùng.
Tất cả các loại bỏ chuỗi con khác mà không được nêu rõ trong phần giải thích sẽ dẫn đến lỗi cú pháp hoặc kiểu.
Chỉnh sửa 1: length(explode t)
chỉ là size t
.
Chỉnh sửa 2: Cảm ơn Anders Kaseorg vì một cách tiếp cận khác nhau và chỉ ra một "lỗ hổng".