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?
Criando uma biblioteca de funções para muatar variáveis globais arbitrárias
-
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?
Solução 2
Outras dicas
Este é um estilo ruim e um desperdício do seu tempo.
push-something
é equivalente acons
.push-cdr
é não funcional: ele modifica o argumento no local ou falha com um erro emnil
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