";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
Versión sin comillas: Pruébelo en codingground.
Versión citada: Pruébelo en codingground.
Tenga en cuenta que la salida se parece a esto
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
porque el código se interpreta declaración por declaración (cada ;una termina una declaración) y muestra el valor y el tipo de cada declaración.
Antecedentes
En SML hay una quine de la forma <code>"<code in quotes>":
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
y uno en la forma "<code in quotes>"<code>:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
Ambos se basan en el hecho de que la parte <code>no contiene comillas y, por lo tanto, se puede citar sin la necesidad de escapar de nada, el" necesidad de generar la quine está dada porstr(chr 34) .
También dependen en gran medida del identificador implícito it que se utiliza cuando no se proporciona un identificador explícito en una declaración.
En el primer quine se str(chr 34);une ita la cadena que contiene ", fn x=>comienza una función anónima tomando un argumento x, luego concatena x^it^x^ite imprime la cadena resultante. Esta función anónima se aplica directamente a una cadena que contiene el código del programa, por lo que la concatenación x^it^x^itproduce<code>"<code>" .
La segunda quine comienza solo con el código del programa como cadena ";str(chr 34)^it;print(it^it)";que está vinculada it. Luego str(chr 34)^it;concatena una cita al comienzo de la cadena y, como tampoco se proporciona un identificador explícito, la cadena resultante "<code>está vinculada it. Finalmente print(it^it)concatena la cadena produciendo la misma "<code>"<code>que luego se imprime.
Explicación
Editar: ya no está actualizado con la versión de 108 bytes, sin embargo, uno podría entenderlo también después de leer esta explicación.
La cita segura para presupuestos combina los dos enfoques anteriores y es en sí misma de la forma "<code>"<code>. Poner esto de nuevo entre comillas rinde""<code>"<code>" , por lo que obtenemos una cadena vacía y luego una quine de la otra forma.
Eso significa que el "<code>identificador le da al programa su propia fuente en la forma it, o ites justo "y se nos da nuestra propia fuente <code>como argumento y, por lo tanto, debe ser una función que maneje dicho argumento.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
Para identificar en qué caso estamos, verificamos si el tamaño de ites mayor que 1. Si no ites así, entonces "estamos y estamos en el segundo caso, por lo que la parte elsedevuelve una función anónima fn x=>print(it^it^x^it^x^it)que luego se llama porque es seguida por la fuente como cadena . Tenga it^it^en cuenta el inicio que se necesita para la cadena vacía al comienzo del programa.
Si size ites mayor que 1, estamos en la parte theny solo actuamos print(it^it), ¿verdad? No del todo, porque olvidé decirte que SML está fuertemente tipado, lo que significa que un condicional if <cond> then <exp_1> else <exp_2>siempre debe tener el mismo tipo, lo que nuevamente significa que las expresiones <exp_1>y <exp_2>deben tener el mismo tipo. Ya sabemos el tipo de la elseparte: una función anónima que toma una cadena y luego llama printtiene tipo string -> <return type of print>y printtiene tipo string -> unit( unites de alguna manera similar a voiden otros idiomas), por lo que el tipo resultante es nuevamentestring -> unit .
Entonces, si la thenparte fuera solo la print(it^it)que tiene tipo unit, obtendríamos un error de desajuste de tipo. ¿Y qué tal fn _=>print(it^it)? ( _es un comodín para un argumento que no se usa) Esta función anónima por sí sola tiene un tipo 'a -> unitdonde 'arepresenta un tipo arbitrario, por lo tanto, en el contexto de nuestro condicional que impone un string -> unittipo, esto funcionaría. (La variable type 'ase instancia con type string.) Sin embargo, en este caso no imprimiríamos nada ya que nunca se llama a la función anónima. Recuerde, cuando vamos en la parte- thenel código general es "<code>"<code>, entonces la parte se <code>evalúa como una función pero, como nada viene después, no se llama.
En su lugar se utiliza un sequentialisation que tiene la forma (<exp_1>; ...; <exp_n>)en <exp_1>que <exp_n-1>pueden tener tipos arbitrarios y el tipo de <exp_n>proporciona el tipo de todo el sequentialisation. Desde un punto de vista funcional, los valores de <exp_1>to <exp_n-1>simplemente se descartan, sin embargo, SML también admite construcciones imperativas, por lo que las expresiones pueden tener efectos secundarios. En resumen, tomamos (print(it^it);print)como parte then, imprimiendo primero y luego devolviendo la función printque tiene el tipo correcto.