Dicas para jogar golfe em Tcl

15

Que dicas gerais você tem para jogar golfe em Tcl? Estou procurando idéias que possam ser aplicadas aos problemas de código de golfe em geral que sejam pelo menos um pouco específicos ao Tcl (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

Johannes Kuhn
fonte

Respostas:

7

Use em lmapvez disso foreach. Isso requer Tcl 8.6.

A sintaxe é a mesma, mas lmapretorna uma lista com o resultado de cada loop.

Johannes Kuhn
fonte
4

Na minha resposta /codegolf//a/107557/29325 , posso demonstrar:

  1. Geralmente set j 0;while \$j<$n;{...;incr j}é mais curto que o equivalentefor {set j 0} {$j<$n} {incr j} {...}

  2. Quando a variável de loop começa em 1, podemos fazer o incremento como parte da whilecondição de teste, evitando escrever antes set i 1desnecessariamente: em while {[incr i]<=$n} {...}vez deset i 1;while \$i<=$n;{...;incr i}

ATENÇÃO : Só é possível fazer 2. no caso de um loop externo! Não pude aplicá-lo à minha jvariável, pois ela precisa ser redefinida para 1 na parte externa de seu próprio loop interno! E incr jadquiriria o valor definido na última etapa do loop interno, em vez de pegar uma variável indefinidaj para assumir 0e incrementá-la 1!

sergiol
fonte
4

Às vezes, vale a pena usar time {script} nonde nestá o número de iterações em vez de um normal whileou forloop. Embora timeo objetivo não seja repetitivo, o efeito alcançado é o mesmo.

Fiz alterações recentemente nas minhas próprias respostas seguindo esta direção.

ATUALIZAÇÃO: Acabei de descobrir uma armadilha fácil de cair: você não pode substituir a forou a whilepor um timebloco, se ele contiver a breakou a continue.

sergiol
fonte
3

Use o shell interativo. Isso permite abreviar os nomes dos comandos, contanto que apenas 1 comando comece com as letras restantes.

Exemplo:

  • gets -> ge
  • lassign -> las
  • expr -> exp
  • puts -> pu

E as soluções interativas são gratuitas: P

Antecedentes :

Quando tclshexecutado com um terminal como dispositivo de entrada, define a variável tcl_interactivepara 1. Isso faz com que unknown(procedimento padrão que será chamado se um comando não puder ser encontrado) procure por comandos que começam com esse nome.

Desvantagem: imprimirá o resultado de cada linha, use em ;vez de novas linhas.
Ohh, e pode chamar comandos externos como w, que é uma boa abreviação de while.

Johannes Kuhn
fonte
3

Subcomandos e opções podem (geralmente) ser abreviados. Isso pode economizar um pouco, mas você deve testar, pois nem tudo pode ser reduzido dessa maneira (regsub as opções não podem, por exemplo).

Você pode usar isso com a mágica de namespacefazer algumas coisas realmente más. Considere isto:

namespace exp *;namespace en cr -c ?

Depois disso, ?agora é um comando mágico que permite abreviar qualquer comando Tcl global, e tudo sem a incerteza desagradável de se mexer unknown.

Donal Fellows
fonte
2

Estou usando o Tcl 8.0.5, mas acredito que o seguinte seja aplicável a todas as versões recentes.

  1. Use renamepara renomear rename:

    rename rename &
    

    O &pode ser qualquer identificador; &apenas me lembra "referências" em C.

  2. Use o renomeado renamepara renomear set:

    & set =
    

    Novamente, =pode ser qualquer identificador; =é apenas intuitivo para mim.

  3. Agora, renomeie outros comandos que valham a pena renomear, por exemplo

    & regsub R
    & string S
    & while W
    

    Um comando vale a pena renomear se, dado seu comprimento n , e as ocorrências k , k (n-1) - (n + 4)> 0 . Resolvendo para k , a fórmula se torna k > (n+4)/(n-1). Aqui está uma tabela de referência que facilita:

    length of       minimum         example(s)
    command         occurrences
    ------------------------------------------------
    2               6               if (consider renaming to "?")
    3               4               for, set (consider renaming to "=")
    4               3               eval, expr, incr (consider renaming to "+"), info, join, proc, puts, scan
    5               3               break, catch, lsort, split, subst, trace, unset, while
    6               3               format, lindex, lrange, regexp, regsub, rename, return, string, switch
    7               2               foreach, lappend, linsert, llength, lsearch, unknown
    .               2               lreplace
    .               2               continue
    .               2               
    
  4. Em seguida, compacte subcomandos usados ​​com frequência, como

    = I index
    = L length
    

    para que você possa fazer coisas como

    S $I $x 7
    S $L $x
    
  5. Algumas miscelâneas óbvias:

    1. lappend pode definir o primeiro elemento de uma lista se ainda não existir (não é necessário inicializar).
    2. Você pode definir matrizes sem usar array, por exemplo set doesNotExist(7) 43 .
    3. Você pode usar strings ( "a b c") em vez de [list a b c].
    4. Você pode interpolar em cordas assim: foo${a}bar.
    5. Você pode usar em two\ wordsvez de "two words". (Lembre-se, em geral, que para cadeias contíguas sem espaços, aspas duplas podem ser omitidas!)
    6. Você quase sempre pode reescrever fors como whiles para salvar um ou dois caracteres, pois um whilepode verificar e incrementar simultaneamente enquanto forusa blocos separados.
  6. Para programas maiores, aqui está um truque que eu pensei, mas ainda não apliquei:

    proc unknown {c args} {eval [info commands $c*] $args}
    

    Isso emula abreviações de comandos interativos! Custa 54 caracteres, mas agora você pode usar jpara join, sppara split, stpara string, wpara whilee assim por diante.

Andrew Cheong
fonte
1
Se você deseja emular abreviaturas interativos, useinfo script {};set tcl_interactive 1
Johannes Kuhn
Legal, obrigado! Eu creditei você aqui . Contudo, houve alguns problemas com essa técnica que não encontrei na unknownrota: veja aqui e aqui .
Andrew Cheong
A pergunta pede dicas que são um pouco específicas para Tcl. O operador ternário está incluído nas dicas para todos os idiomas .
Peter Taylor
@ PeterTaylor - Obrigado, eu removi essa dica.
Andrew Cheong
2

else é opcional

Como é dito na página de manual , elseestá implícito nas ifconstruções de bloco. Então, o que é

if ... {} else {}

pode se tornar

if ... {} {}

como você pode ver em algumas das minhas respostas.

sergiol
fonte
1

Pode ser que deva ser integrado em outra resposta, mas aqui vai:

Quando a procpossui apenas um parâmetro, ele pode ser escrito como

proc p a {DO THINGS}

ao invés de

proc p {a} {DO THINGS}

O mesmo se aplica a dois parâmetros procusando uma barra invertida; pode ser escrito como

proc p a\ b {DO THINGS}

ao invés de

proc p {a b} {DO THINGS}

Para um número maior de parâmetros, a {}renderização é mais curta.

sergiol
fonte
1

Às vezes, vale a pena substituir as duas setinstruções para concatenar seqüências de caracteres por apenas uma lappenddeclaração. Em uma construção como, pode-se substituir

set s ""

loop {
    # ...
    set s $s\X
}

por

loop {
    # ...
    append s X
}

O appendcomando tem umincr comportamento semelhante, que inicializa uma variável ainda não definida.

Tome cuidado para não erro appendporlappend

sergiol
fonte
1

Se você estiver manipulando uma lista com uma operação que sintaticamente está intercalando entre cada elemento, às vezes você pode joinelementos para executar uma operação específica, em vez de atravessá-la.

Em /codegolf//a/127042/29325, há um exemplo:

puts \n[expr [join [split [read stdin]] +]]

Ele read stdin23 214 52, então, dividir vai dar a lista {23 214 52}. Depois, [join {23 214 52} +]retornará a string 23+214+52. Finalmente expr 23+214+52faz o trabalho de somar

sergiol
fonte
Nesse caso, você pode omitir o split.
Johannes Kuhn
@JohannesKuhn: obrigado. Feito.
sergiol 16/09
1

Se você tem códigos grandes, é possível evitar vários usos de exprusar namespace pat tcl::mathopno início. Ele fornece operação de prefixo-sintaxe como uma função Tcl regular. Por exemplo:

namespace pat tcl::mathop
set sum [+ 1 2 3]
set prod [* {*}{1 2 3 4}]
puts $sum\ $prod

Veja a página oficial do doc mathop

david
fonte
0

Quando você tem várias variáveis ​​que estão setnas linhas subseqüentes, pode usar uma em lassignvez de várias setinstruções para obter o mesmo efeito.

Um exemplo é minha própria resposta /codegolf//a/105789/29325

Para decidir, basta ponderar o número de variáveis ​​(assumindo variáveis ​​de 1 letra, como é esperado no golfe):

  • <5 set é golfista

  • = 5 setelassign gere a mesma contagem de bytes

  • > 5, lassigné golfista

sergiol
fonte