Criando uma biblioteca de funções para muatar variáveis ​​globais arbitrárias

StackOverflow https://stackoverflow.com/questions/20353946

  •  25-08-2022
  •  | 
  •  

Pergunta

ATUALIZAÇÃO: Se eu tenho algumas funções que quero mutações de uma variável global que é aprovada como um argumento de função, alguns podem fazer isso passando apenas o símbolo do global (como no caso de empurrar algo para parte de uma lista) , mas outras funções exigirão que o símbolo seja citado quando for passado para que eu possa acessar o valor do símbolo e mudar a variável externa, necessária para o uso do setQ em uma função. Esta questão é basicamente sobre criar uma interface consistente para um usuário dessas funções sem confundi -las de que às vezes você passa no símbolo, outras vezes você passa no símbolo citado

Exemplo de maneira de otimizar a interface para várias funções, usando um ajudante que tem o mesmo uso sem uso de como a função de mutação funciona:

Aqui estão 2 exemplos básicos da minha técnica:

(defun push-something (global something)
  (push something global)
  global) ;; not necessary to return it here since the 
          ;; preceding line already does, but doing so 
          ;; for consistency with other functions and clarity

(defun push-cdr (global something)
  (push something (cdr global))
  global) ;; must return it if I am going to set the 
          ;; dynamic var to the result of this function, 
          ;; because the preceding line doesn't return the 
          ;; entire new result of the variable

;;; "dirty" function for mutating global variable using "clean" functions above:

(defun set-global (fn global &rest values)
  (setf (symbol-value global) (apply fn (copy-list (eval global)) values)))

Neste último, devo eval a global já que é citado para uso com symbol-value e então eu copy-list de modo a global não é diretamente mutado acidentalmente por qualquer coisa fn Eu escolho (como seria o caso push-cdr o que pode não ser trivial em funções mais complicadas).

Resultado:

CL-USER> (defparameter *g2* nil)
*G2*
CL-USER> (set-global #'push-something '*g2* 5)
(5)
CL-USER> *g2*
(5)
CL-USER> (set-global #'push-cdr '*g2* 99)
(5 99)
CL-USER> *g2*
(5 99)

... e as mesmas funções poderiam ser usadas com *g1* ou *g3* etc por toda a função de acesso set-global.

Isso é um estilo bom ou ruim, ou estou perdendo uma maneira muito melhor de alcançar essa funcionalidade?

Foi útil?

Solução 2

Por que você não se livra de set-global Função completamente, e se você deseja que toda a sua função tenha o mesmo estilo de passar na variável global, apenas faça com que todos eles usem symbol-value Portanto, qualquer pessoa que use essas funções não precisará saber o que faz e quais não exigem uma cotação na frente do nome da variável global sendo aprovado. Muito mais fácil, certo?

Outras dicas

Este é um estilo ruim e um desperdício do seu tempo.

  1. push-something é equivalente a cons.

  2. push-cdr é não funcional: ele modifica o argumento no local ou falha com um erro em nil argumento.

Se você deseja alterar o valor da variável global, usando setf explicitamente é muito mais claro.

Se você deseja modificar os internos de um valor global de alguma maneira intrincada, pode ser necessário escrever uma função especial para isso - mas essa função deve ser agnóstica do fato de estar modificando o valor ligado a uma variável global, em oposição a uma variável lexical.

Em resumo, existem dois problemas ortogonais separados - alterando uma variável global (use setq) e mudar internos de um objeto (seja agnóstico de sua natureza global).

Ps. Não tenho certeza do que você quer dizer com "SETF não altera o valor de uma variável global quando está dentro da função", mas:

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top