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: Дякуємо Андерсу Касеоргу за різний підхід і вказує на "вразливість".