Respostas:
*
para saídaComo você pode produzir deixando uma string na pilha , pode ser útil acumular a string usando, em *
vez de com S
. Digamos que seu desafio foi "pegar uma string e acrescentar um espaço", a maneira de fazer isso com a saída seria:
S( )S
A maneira de fazer isso *
, por outro lado, é um byte mais curto:
( )*
O problema é que, se sua saída tiver muita acumulação, poderá custar bytes para lidar com o elemento de saída na pilha.
Se você precisar usar muito um pedaço de código, faz sentido armazenar esse código na pilha e duplicá-lo e avaliá-lo de vez em quando. Até agora, isso é apenas a programação normal do Underload. Infelizmente, manter um valor na pilha por um longo tempo é difícil e tende a fazer com que seu código fique detalhado, e isso é verdade mesmo que o valor seja uma função e não dados. Isso fica muito pior se você tiver várias funções que precisam ser reutilizadas repetidamente.
No tipo de programa maior que pode se beneficiar de várias funções reutilizadas, uma solução que você pode usar é criar uma função grande que atenda a qualquer um de seus objetivos, dependendo da forma como é chamada (com base no que está embaixo na pilha, ou através de usar mais chamando as sequências que apenas ^
; uma função cuidadosamente escrito pode distinguir ^^
a partir ^:^
de ^*^
partir ^~^
, dando-lhe quatro distintas, seqüências bastante curtas). Você também pode armazenar outras coisas úteis, como seqüências de caracteres que você usa várias vezes, neste "dicionário". Observe que, se você usar o dicionário intensamente, pode fazer sentido torná-lo uma espécie de quine, empurrando uma cópia de si mesmo de volta para a pilha, para que você não precise copiá-lo manualmente com:
poder usá-lo sem perder a capacidade de usá-lo no futuro.
^!!!!^
pesquisa de estilo preferida (que também usei em vários outros exemplos na página, especialmente na seção de minimização). Embora isso possa não dar a pesquisa mais curta.
Como um exemplo simples, a implementação mais comum de booleanos é !()
para false (ou seja, número inteiro 0) e a sequência nula para true (ou seja, número 1), mas se você tiver um problema fortemente baseado no XOR lógico, isso poderá gerar mais É bom usar a string nula para false e ~
true (esse formato de dados pode ser convertido em qualquer outro formato booleano usando (false)~(true)~^!
e permite a implementação muito concisa *
do XOR.
É possível levar esse princípio geral ainda mais longe e usar funções que seu programa precisará posteriormente como parte dos valores de seus dados; isso economiza a necessidade de armazenar as funções e os dados separadamente na pilha. Isso pode tornar o fluxo de controle um pouco mais confuso, mas, quando se joga golfe, a manutenção geralmente precisa ficar no banco de trás, e não é como se o Underload fosse tão utilizável de qualquer maneira.
(!)
e (~!)
para booleanos, mas seu caminho parece melhor.
A maneira funcionalmente pura de diminuir um numeral da Igreja é usar a função predecessora do cálculo lambda:
\n.n(\p.\z.z($(pT))(pT))(\z.z0[whatever you define the predecessor of 0 to be])
Onde 0 = \ x. \ Yy, T = \ x. \ Yx e $ é o sucessor.
Reescrito no Underload, são 28 bytes:
(!())~(!())~(!:(:)~*(*)*~)~^!
Está tudo bem, mas podemos explorar algumas das propriedades úteis do Underload, a saber, que :!
e ()*
do são não-ops. Isso significa que, para um número n
, :ⁿ!!()()*ⁿ
(onde cⁿ
é c
repetido n
vezes) produz n-1. Por exemplo, fazer isso para o numeral da igreja 3 gera o seguinte:
:::!!()()***
Removendo pares no-op, obtemos:
:*
Qual é 2.
Portanto, esta é a nova e mais curta operação predecessora:
:(:)~^(!!()())*~(*)~^*
Este é 7 bytes mais curto.
(()~(:))~:(^!!())*~(*)~^**
ainda será 3 bytes mais curto.
Na verdade, a subcarga possui duas pilhas - a pilha de strings e a pilha de comandos que compõem o código-fonte. A ^
instrução Underload permite mover as strings da pilha anterior para a última. Ao fazer isso, podemos economizar muita manipulação desnecessária de pilhas.
Por exemplo, digamos que temos (a)(b)(c)
na pilha principal e gostaríamos de concatenar os dois elementos inferiores, ignorando (c)
, para obter (ab)(c)
. A maneira ingênua de fazer isso é girar a pilha para obter (c)(a)(b)
e concantenar e trocar de volta:
a~a~*~a*^*~
Isto é mau. Usar a~a~*~a*^
para girar a pilha dessa maneira é extremamente caro e deve ser evitado quando possível. Ao colocar (c)
no espaço do programa, isso pode ser feito quatro bytes mais curto:
a(*)~*^
A idéia é seguir as instruções que você deseja executar e, em seguida, adicionar uma instrução para (c)
retroceder no final e avaliar o resultado. Isso significa que não precisamos nos preocupar (c)
até que seja adiada depois que terminarmos.
(*)~a*^
, o que eu acho que é um pouco mais compostável. Essencialmente ~a*^
é o dip
comando da Joy.
eval
comando, nunca vi uma linguagem assim antes.