;gnu clisp 2.49 (print "Hello, world!") (defmacro toggle (obj) `(setf ,obj (not ,obj))) (print ;; 빡치게 두번 실행됨. 한번만 실행되어야 하는데 ;; 토글 안에서 obj를 두개 넣기 때문임. (let ((lst '(t nil t)) (i -1)) (toggle (nth (incf i) lst)) lst) ) (T NIL T) ; 안됨 첫번째 T가 NIL이 되어야함. ;; 형태를 더 보면 (setf (nth (incf i) lst) (not (nth (incf i) lst))) ;; 이렇게 (incf i)를 두번 부르게 된다. ;; 'toggle'의 표현식 인수를 단순히 'setf'의 첫 번째 인수로 삽입하는 것만으로는 충분하지 않다. ; 우리는 들어온 표현식의 내부를 확인해봐야 한다. ; 하위 양식이 포함 된 경우, 부작용이있는 경우 하위 양식을 분리하여 개별적으로 평가해야합니다. ; 쉽게 만들기 위해. Common Lisp는 setf에서 제한된 매크로 클래스를 자동으로 정의하는 매크로를 제공. ; 이 매크로가 setf의 제한된 매크로 클래스 인 'defined-modify-macro'. ; 이름, 추가적인 매개변수(after the generalized variable), 그리고 함수이름 3개의 매개변수를 받는다. ; Using define-modify-macro, we could define toggle as follows: ; (define-modify-macro toggle () not) ; 이 코드는 "to evaluate an expression of the form (toggle place), find the location specified by place, ; and if the value stored there is val, replace it with the value of (not val)"이다. ; (toggle place)형태의 표현식을 평가하려면, place로 특정되는 위치를 찾고, 값이 있다면 그걸 val로 하자, 그 val을 (not value)로 치환하라. (define-modify-macro toggle () not) ;; 이렇게만 하면 된다. 테스트해보자. (let ((lst '(t nil t)) (i -1)) (toggle (nth (incf i) lst)) lst) (NIL NIL T) ; 잘됨 ;; 좀더 일반화 할 수 있다. ;setf와 setq는 임의의 갯수의 인수를 취할 수 있으므로 toggle도 마찬가지로 가능할 것이다. ; modify-macro 위에 다른 매크로를 정의하여이 기능을 추가 할 수 있습니다. ;Fig 12.1로 더 자세히 보자. (defmacro allf (val &rest args) (with-gensyms (gval) `(let ((,gval ,val)) (set ,@(mapcan #'(lambda (a) (list a gval)) args))))) (defmacro nilf (&rest args) `(allf nil ,@args)) (defmacro tf (&rest args) `(allf t ,@args)) (defmacro toggle (&rest args) `(progn ,@(mapcar #'(lambda (a) '(toggle2 ,a)) args))) (define-modify-macro toggle2 () not) ;; 이건 이전에 만든 토글 (defmacro toggle (obj) `(setf ,obj (not ,obj)))
2019년 9월 11일 수요일
[on lisp] 12.2 The Multiple Evaluation Problem
피드 구독하기:
댓글 (Atom)
댓글 없음:
댓글 쓰기