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)"]
Спробуйте в Інтернеті!
Для MLton повні програми SML є або виразами, обмеженими і закінченими ;
(наприклад print"Hello";print"World";
), або деклараціями з ключовими словами var
та fun
(наприклад var _=print"Hello"var _=print"World"
), де_
є шаблоном, який також може бути замінений будь-яким ім'ям змінної.
Перший варіант марний для незайманого програмування, оскільки сам ;
по собі є дійсною програмою (яка нічого не робить, але і не помиляється). Проблема другого підходу полягає в тому, що декларації, подібні до цього, var _=print"Hello"
можуть бути скорочені до просто var _="Hello"
(або навіть var _=print
), оскільки декларація зvar
працює до тих пір, поки правий бік є дійсним виразом або значенням SML (SML є функціональною мовою, тому функції можуть бути використовується також як значення).
На цей момент я був готовий оголосити незаймане програмування в SML неможливим, коли випадково натрапив на відповідність шаблонів у val
-деклараціях. Виявляється, синтаксис для декларацій не є, val <variable_name> = <expression>
але val <pattern> = <expression>
там, де шаблон може складатися з змінних імен, констант і конструкторів. Оскільки print
функція має тип string -> unit
, ми можемо використовувати зіставлення з зразком на unit
-value ()
для забезпечення , що функція друку фактично застосовується до рядка: val()=print"Hey"
. При такому підході видалення print
або "Hey"
призводить до Pattern and expression disagree
помилки.
З таким способом первозданної друку під рукою наступним кроком є написання квіта, перш ніж нарешті потрібно додати ще кілька збережень для збереження. Раніше я використовував просту техніку SML quine (див. Історію редагування ), але Андерс Касеорг зазначив інший підхід, який може зберегти кілька байт у його випадку. Він використовує вбудовану String.toString
функцію для обробки вхідних рядків і має загальну форму <code>"<data>"
, де "<data>"
є рядок, що утворився code
раніше:
val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"
Це робоча квітка, але ще не незаймана. Перш за все Андерс Касеорг з'ясував, що MLton приймає єдину цитату "
як код, не створюючи помилок, а це означає, що ми не можемо мати код, що закінчується цитатою, як зазначено вище. Найкоротшим способом запобігти цьому було б загортати все val()=
в пару круглих дужок, проте тоді код може бути зведений до val()=()
. Другий найкоротший спосіб, який я знайшов - це використовувати val()=hd[ ... ]
, тобто ми загортаємо все до списку і повертаємо його перший елемент, щоб зробити диспетчером типу щасливим.
Щоб переконатися, що жодна частина рядка даних не може бути видалена, не помітивши, val
знов-таки стане в нагоді відповідність шаблонів у -декларуваннях: Довжина остаточного рядка, який слід надрукувати (і, таким чином, довжина програми), повинна дорівнювати 195, так ми можемо записати let val t=... val 195=size t in print t end
в тілі fn
абстракції замість print(...)
. Видалення частини рядка призводить до довжини менше 189, тим самим спричиняючи викид для Bind
виключення.
Залишилося питання: весь val 195=size t
чек можна просто зняти. Ми можемо запобігти цьому, розширивши чек на збіг на кортеж:, val t=... val(216,u)=(n+size t,t)in print u end
таким чином, що видалення перевірки призводить до незв'язаної змінної u
.
Загалом, це дає наступне 195-байтне рішення:
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)"]
Застосування трюку з гольфу щодо використання назв змінних операторів, таких як !
, $
а не %
замість них n
, t
а також u
для економії білого простору (див. Цю пораду ) призводить до остаточної версії 182 байтів.
Усі інші видалення підрядків, які там, де прямо не вказано в поясненні, повинні призвести до синтаксису або помилки типу.
Правка 1: length(explode t)
просто size t
.
Редагування 2: Дякуємо Андерсу Касеоргу за різний підхід і вказує на "вразливість".