push
работает иначе, когда ему передается символ или список в качестве второго аргумента. Возможно, вы поймете это лучше, если сделаете macroexpand
на двух разных.
(macroexpand '(push 99 (rest var)))
;;==>
(let* ((#:g5374 99))
(let* ((#:temp-5373 var))
(let* ((#:g5375 (rest #:temp-5373)))
(system::%rplacd #:temp-5373 (cons #:g5374 #:g5375)))))
Теперь большая часть этого состоит в том, чтобы не оценивать аргументы более одного раза, поэтому мы можем в этом случае переписать его так:
(rplacd var (cons 99 (rest var)))
Теперь это изменяет cdr
var таким образом, что каждая привязка к одному и тому же значению или спискам, имеющим один и тот же объект в своей структуре, изменяется. Теперь давайте попробуем другой:
(macroexpand '(push 5 something))
; ==>
(setq something (cons 5 something))
Здесь создается новый список, начинающийся с 5, и изменяются локальные функции, привязывающие что-то к тому значению, которое в начале указывало на исходную структуру. Если у вас есть исходная структура в переменной lst
, она не изменится, поскольку это совершенно другая привязка, чем something
. Вы можете решить свою проблему с помощью макроса:
(defmacro just-push (lst)
(if (symbolp lst)
`(push 5 ,lst)
(error "macro-argument-not-symbol")))
Это принимает только переменные в качестве аргумента и преобразует его в новый список, имеющий 5 в качестве первого элемента и исходный список в качестве хвоста. (just-push x)
— это просто сокращение от (push 5 x)
.
Просто быть чистым. На диалекте алгола эквивалентный код будет выглядеть примерно так:
public class Node
{
private int value;
private Node next;
public Node(int value, Node next)
{
this.value = value;
this.next = next;
}
public static void pushRest(Node var)
{
Node n = new Node(99, var.next); // a new node with 99 and chained with the rest of var
var.next = n; // argument gets mutated to have new node as next
}
public static void justPush(Node var)
{
var = new Node(5, var); // overwrite var
System.out.print("var in justPush is: ");
var.print();
}
public void print()
{
System.out.print(String.valueOf(value) + " ");
if ( next == null )
System.out.println();
else
next.print();
}
public static void main (String[] args)
{
Node n = new Node( 10, new Node(20, null));
n.print(); // displays "10 20"
pushRest(n); // mutates list
n.print(); // displays "10 99 20"
justPush(n); // displays "var in justPush is :5 10 99 20"
n.print(); // displays "10 99 20"
}
}
person
Sylwester
schedule
03.12.2013
something
и иметь локальные переменныеsomething
. Используйте*something*
в качестве имени глобальной переменной. - person Rainer Joswig   schedule 03.12.2013