Às vezes, preciso definir o mesmo valor para várias variáveis.
Em Python, eu poderia fazer
f_loc1 = f_loc2 = "/foo/bar"
Mas no Elisp, estou escrevendo
(setq f_loc1 "/foo/bar" f_loc2 "/foo/bar")
Gostaria de saber se existe uma maneira de conseguir isso usando "/foo/bar"
apenas uma vez?
source
etarget
para o mesmo caminho no início e eu posso mudartarget
mais tarde, como defini-los, então?Respostas:
setq
retorna o valor, então você pode:Se você não quiser confiar nisso, use:
Pessoalmente, eu evitaria o último e escreveria:
ou mesmo
E a primeira abordagem que eu usaria apenas em circunstâncias bastante especiais, onde ela realmente enfatiza a intenção, ou quando a alternativa seria usar a segunda abordagem ou então
progn
.Você pode parar de ler aqui se o texto acima o fizer feliz. Mas acho que é uma boa oportunidade para avisar você e outras pessoas a não abusarem de macros.
Por fim, embora seja tentador escrever uma macro como
setq-every
"porque isso é lisp e nós podemos", recomendo fortemente que não o faça. Você ganha muito pouco fazendo isso:Mas, ao mesmo tempo, você torna muito mais difícil para outros leitores ler o código e ter certeza do que acontece.
setq-every
pode ser implementado de várias maneiras e outros usuários (incluindo um futuro você) não podem saber qual deles o autor escolhe, apenas observando o código que o utiliza. [Eu originalmente fiz alguns exemplos aqui, mas esses foram considerados sarcásticos e desmedidos por alguém.]Você pode lidar com essa sobrecarga mental toda vez que olhar
setq-every
ou apenas viver com um único personagem extra. (Pelo menos no caso em que você precisa definir apenas duas variáveis, mas não me lembro, tive que definir mais de duas variáveis para o mesmo valor de uma só vez. Se você precisar fazer isso, provavelmente há algo errado. com o seu código.)Por outro lado, se você realmente usar essa macro mais do que meia dúzia de vezes, o indireto adicional poderá valer a pena. Por exemplo, eu uso macros como
--when-let
nadash.el
biblioteca. Isso torna mais difícil para quem o encontra primeiro no meu código, mas superar essa dificuldade no entendimento vale a pena porque é usado mais do que apenas algumas vezes e, pelo menos na minha opinião, torna o código mais legível .Alguém poderia argumentar que o mesmo se aplica
setq-every
, mas acho que é muito improvável que essa macro em particular seja usada mais do que algumas vezes. Uma boa regra geral é que, quando a definição da macro (incluindo a sequência de documentos) adiciona mais código do que o uso da macro remove, a macro provavelmente é um exagero (embora o contrário não seja necessariamente verdadeiro).fonte
setq
que você pode fazer referência a ele é novo valor, então você poderia usar essa monstruosidade muito:(setq a 10 b a c a d a e a)
que conjuntos abcd e e a 10.Uma macro para fazer o que você deseja
Como um exercício de uma espécie:
Agora tente:
Como funciona
Como as pessoas têm curiosidade em saber como isso funciona (de acordo com os comentários), aqui está uma explicação. Para realmente aprender a escrever macros, escolha um bom livro Common Lisp (sim, Common Lisp, você poderá fazer o mesmo no Emacs Lisp, mas o Common Lisp é um pouco mais poderoso e possui melhores livros, IMHO).
Macros operam em código bruto. Macros não avaliam seus argumentos (ao contrário de funções). Portanto, temos aqui uma avaliação
value
e uma coleção devars
, que para nossa macro são apenas símbolos.progn
agrupa váriassetq
formas em uma. Essa coisa:Apenas gera uma lista de
setq
formulários, usando o exemplo do OP, será:Veja, o formulário está dentro do formulário de aspas anteriores e é prefixado com uma vírgula
,
. Dentro do formulário com aspas retroativas, tudo é cotado como de costume, mas,
a avaliaçãomapcar
é ativada temporariamente, e toda a avaliação é avaliada no momento da macroexpansão.Finalmente
@
remove os parênteses externos da lista comsetq
s, para obtermos:As macros podem transformar arbitrariamente seu código-fonte, não é ótimo?
Uma ressalva
Aqui está uma pequena ressalva: o primeiro argumento será avaliado várias vezes, porque essa macro se expande essencialmente para o seguinte:
Veja bem, se você tiver uma variável ou string aqui, tudo bem, mas se você escrever algo como isto:
Então sua função será chamada mais de uma vez. Isso pode ser indesejável. Aqui está como corrigi-lo com a ajuda de
once-only
(disponível no pacote MMT ):E o problema se foi.
fonte
value
no momento da expansão macro.(macroexpand '(setq-every user-emacs-directory f-loc1 f-loc2))
->(progn (setq f-loc1 user-emacs-directory) (setq f-loc2 user-emacs-directory))
. Sevalue
fosse avaliado no momento da macroexpansão, seria substituído por uma string real. Você pode colocar uma chamada de função com efeitos colaterais, no lugar devalue
, ela não será avaliada até que o código expandido seja executado, tente.value
como argumento de macro não é avaliado automaticamente. O problema real é quevalue
será avaliado várias vezes, o que pode ser indesejável,once-only
pode ajudar aqui.mmt-once-only
(que requer um dep externo), você pode usarmacroexp-let2
.set
, para não quebrarsetq
em uma macro. Ou apenas usesetq
com vários argumentos, incluindo a repetição de argumentos.Como você pode usar e manipular símbolos no lisp, você pode simplesmente fazer um loop sobre uma lista de símbolos e usá-los
set
.fonte