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)"]
Wypróbuj online!
W przypadku MLton pełne programy SML są albo wyrażeniami ograniczonymi i zakończonymi ;(np. print"Hello";print"World";) Lub deklaracjami ze słowami kluczowymi vari fun(np. var _=print"Hello"var _=print"World"), Gdzie _znajduje się symbol wieloznaczny, który można również zastąpić dowolną nazwą zmiennej.
Pierwsza opcja jest bezużyteczna dla nieskazitelnego programowania, ponieważ ;sama w sobie jest poprawnym programem (który nic nie robi, ale też nie popełnia błędów). Problem z drugim podejściem polega na tym, że deklaracje takie var _=print"Hello"można skrócić do tylko var _="Hello"(lub nawet var _=print), ponieważ deklaracja zvar działa tak długo, jak długo prawa strona jest prawidłowym wyrażeniem lub wartością SML (SML jest językiem funkcjonalnym, więc funkcje mogą być używane również jako wartości).
W tym momencie byłem gotowy ogłosić, że nieskazitelne programowanie w SML jest niemożliwe, kiedy przez przypadek natknąłem się na dopasowanie wzorca w valdeklaracjach. Okazuje się, że składnia deklaracji nie jest, val <variable_name> = <expression>ale val <pattern> = <expression>gdzie wzorzec może składać się z nazw zmiennych, stałych i konstruktorów. Ponieważ printfunkcja ma typ string -> unit, możemy użyć mecz wzór na unit-value ()egzekwować że funkcja drukowania jest faktycznie stosowane do napisu: val()=print"Hey". Przy takim podejściu usunięcie jednego printlub "Hey"powoduje Pattern and expression disagreebłąd.
Mając ten nieskazitelny druk pod ręką, następnym krokiem jest napisanie quine, zanim w końcu trzeba będzie dodać jeszcze więcej opcji ochrony przed zapisem. Wcześniej korzystałem z łatwej techniki quine SML (patrz historia wersji ), ale Anders Kaseorg wskazał inne podejście, które może zaoszczędzić trochę bajtów w jego przypadku. Używa wbudowanej String.toStringfunkcji do obsługi łańcucha znaków ucieczki i ma ogólną formę <code>"<data>", gdzie "<data>"jest łańcuchem znaków codepoprzedzających:
val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"
To działa quine, ale jeszcze nieskazitelne. Przede wszystkim Anders Kaseorg odkrył, że MLton akceptuje pojedynczy cytat "jako kod bez powodowania błędów, co oznacza, że nie możemy mieć kodu kończącego się cytatem jak powyżej. Najkrótszym sposobem, aby temu zapobiec, jest zawinięcie wszystkiego val()=w parę w nawiasach, jednak kod można zredukować do val()=(). Drugim najkrótszym sposobem, jaki znalazłem, jest użycieval()=hd[ ... ] , tzn. Zawijamy wszystko do listy i zwracamy jej pierwszy element, aby uszczęśliwić sprawdzanie typów.
Aby upewnić się, że żadna część ciągu danych nie może zostać usunięta bez zauważenia, valponownie przydaje się dopasowywanie wzorca w -deklaracjach: Długość końcowego ciągu do wydrukowania (a zatem długości programu) powinna wynosić 195, więc zamiast tego możemy pisać let val t=... val 195=size t in print t endw ciele fnabstrakcji print(...). Usunięcie części ciągu powoduje, że długość jest mniejsza niż 189, powodując w ten sposóbBind wyjątku.
Pozostaje jeszcze problem: cały val 195=size tczek można po prostu porzucić. Możemy temu zapobiec, rozszerzając czek, aby pasował do krotki: val t=... val(216,u)=(n+size t,t)in print u endtak, że usunięcie czeku powoduje powstanie niezwiązanej zmienneju .
W sumie daje to następujące 195 bajtowe rozwiązanie:
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)"]
Stosując podstęp golfa z użyciem nazwy zmiennych takich jak operator !, $i %zamiast n, ti uaby zaoszczędzić trochę spacji (patrz tę końcówkę ) prowadzi do ostatecznej wersji 182 bajtów.
Wszystkie inne usunięcia podciągów, które nie zostały wyraźnie określone w objaśnieniu, powinny skutkować błędem składni lub typu.
Edycja 1: length(explode t) jest po prostu size t.
Edycja 2: Podziękowania dla Andersa Kaseorga za inne podejście quine i wskazanie „podatności”.