Pergunta para iniciantes no Common Lisp:
Como fazer com que meu procedimento retorne objeto procedimental distinto com sua própria ligação local cada vez que for chamada? Atualmente, uso let para criar o estado local, mas duas chamadas de função estão compartilhando o mesmo estado local. Aqui está o código,
(defun make-acc ()
(let ((balance 100))
(defun withdraw (amount)
(setf balance (- balance amount))
(print balance))
(defun deposit (amount)
(setf balance (+ balance amount))
(print balance))
(lambda (m)
(cond ((equal m 'withdraw)
(lambda (x) (withdraw x)))
((equal m 'deposit)
(lambda (x) (deposit x)))))))
;; test
(setf peter-acc (make-acc))
(setf paul-acc (make-acc))
(funcall (funcall peter-acc 'withdraw) 10)
;; Give 90
(funcall (funcall paul-acc 'withdraw) 10)
;; Expect 90 but give 80
Devo fazê-lo de outra maneira? A minha maneira de escrever está errada? Alguém pode me ajudar a tirar essa dúvida? Desde já, obrigado.
lisp
common-lisp
state
let
netherwave
fonte
fonte
Respostas:
Observe que, mesmo após o
defun
problema -is-global ser resolvido, você precisa de muito menos máquinas do que precisa fazer algo assim. Por exemplo:Então
Obviamente,
account-operation
é apenas uma conveniência.fonte
Talvez você queira orientação a objetos?
Uso:
Podemos criar contas com outro saldo:
Para mais, sugiro o livro de receitas: https://lispcookbook.github.io/cl-cookbook/clos.html
fonte
Uma regra geral é que
defun
deve ser usada apenas ao definir uma função no nível superior. Para definir funções locais, os dois operadores especiaisflet
elabels
podem ser usados ( manual ).Por exemplo:
labels
é comoflet
, mas é usado quando há definições recursivas.Então você não precisa retornar funções dentro da função retornada por
make-acc
, mas nela você pode simplesmente executar a operação necessária:A chamada será mais simples e retornará o valor esperado:
Por fim, se você quiser, também pode devolver duas funções diferentes para realizar depósito e retirada na conta:
usando isso, por exemplo, como:
fonte
O único problema sério aqui é
defun
que, em comum, o lisp não é usado para definir funções locais.Você pode, por exemplo, usar
lambda
s para essas operações, especialmente se desejar retornar lambdas ...Observe que eu usei, em
let*
vez de,let
porque você precisa poder verbalance
nas duas ligações a seguir.fonte