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)"]
Experimente online!
Para o MLton, os programas SML completos são expressões delimitadas e finalizadas por ;( por exemplo print"Hello";print"World";) ou declarações com as palavras var- funchave e (por exemplo var _=print"Hello"var _=print"World") onde _é um curinga que também pode ser substituído por qualquer nome de variável.
A primeira opção é inútil para a programação original, porque ;por si só é um programa válido (que não faz nada, mas também não erra). O problema com a segunda abordagem é que declarações como var _=print"Hello"podem ser encurtadas para apenas var _="Hello"(ou até mesmo var _=print) porque a declaração varfunciona desde que o lado direito seja uma expressão ou valor SML válido (SML é uma linguagem funcional, portanto, as funções podem ser usado como valores também).
Nesse ponto, eu estava pronto para declarar impossível a programação primitiva no SML, quando por acaso me deparei com a correspondência de padrões nas valdeclarações -. Acontece que a sintaxe para declarações não é val <variable_name> = <expression>mas val <pattern> = <expression>, onde um padrão pode consistir em nomes de variáveis, constantes e construtores. À medida que a printfunção tem tipo string -> unit, podemos usar uma correspondência de padrão na unit-valor ()para impor que a função de impressão é realmente aplicado à string: val()=print"Hey". Com essa abordagem, a remoção de um printou "Hey"resulta em um Pattern and expression disagreeerro.
Com esta forma de impressão impecável em mãos, o próximo passo é escrever um quine, antes de finalmente ser necessário adicionar mais salvaguardas. Anteriormente, usei uma técnica fácil de SML Quine (consulte o histórico de revisões ), mas Anders Kaseorg apontou uma abordagem diferente que pode economizar alguns bytes no seu caso. Ele usa a String.toStringfunção interna para lidar com escape de string e é da forma geral <code>"<data>", onde "<data>"é um string escapado do codeanterior:
val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"
Esta é uma solução prática, mas ainda não intocada. Antes de tudo, Anders Kaseorg descobriu que o MLton aceita uma única citação "como código sem gerar erros, o que significa que não podemos ter o código terminado em uma citação como acima. A maneira mais curta de evitar isso seria agrupar tudo depois val()=entre parênteses, no entanto, o código poderia ser reduzido para val()=(). A segunda maneira mais curta que encontrei é usar val()=hd[ ... ], ou seja, agrupamos tudo em uma lista e retornamos seu primeiro elemento para deixar o verificador de tipos feliz.
Para garantir que nenhuma parte da sequência de dados possa ser removida sem ser notada, as valdeclarações de correspondência de padrões são úteis novamente: O comprimento da sequência final a ser impressa (e, portanto, a duração do programa) deve ser igual a 195, portanto podemos escrever let val t=... val 195=size t in print t endno corpo da fnabstração em vez de print(...). A remoção de uma parte da cadeia resulta em um comprimento menor que 189, fazendo com que uma Bindexceção seja lançada.
Ainda resta um problema: todo o val 195=size tcheque pode ser simplesmente descartado. Podemos evitar isso expandindo a verificação para corresponder a uma tupla:, de val t=... val(216,u)=(n+size t,t)in print u endmodo que a remoção da verificação resulte em uma variável não acoplada u.
No total, isso gera a seguinte solução de 195 bytes:
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)"]
A aplicação do truque de golfe ao usar nomes de variáveis de operador como !, $e em %vez de n, te upara economizar espaço em branco (consulte esta dica ), leva à versão final de 182 bytes.
Todas as outras remoções de substring que não foram explicitamente declaradas na explicação devem resultar em erro de sintaxe ou de tipo.
Editar 1: length(explode t) é justo size t.
Edit 2: Obrigado a Anders Kaseorg por uma abordagem diferente do quine e por apontar uma "vulnerabilidade".