Common Lisp에서는 setf macro가 container에 대해 mutation할 때, 매크로로 처리한다.
즉, container에 대한 read 함수와 별개로 write 함수가 구현되어 있어야 한다. (여기서는 rplaca)
예제:
* (let ((a (list 1 2))) (setf (nth 0 a) 3) a)
(3 2)
* (macroexpand '(setf (nth 0 a) 3))
(LET* ((#:LIST (NTHCDR 0 A)) (#:NEW 3)) (SB-KERNEL:%RPLACA #:LIST #:NEW))
Clojure에서는 mutation이 필요한 것은 atom 등으로 되어 있어야 한다.
그래서 container에 대해 read 함수만 있고 특별한 mutation 함수가 없어도 된다. container에는 box를 넣어 놓고, box에 물건을 바꿔 넣는다. (마치 C++의 pass by reference 개념과 비슷하다.)
이렇게 mutation할 수 있는 type을 따로 만드는 것이 우아한 방법인 것 같다. 구현도 편하고...
코드 예제:
Clojure 1.10.1
user=> (def a (list (atom 1) (atom 2)))
#'user/a
user=> a
(#object[clojure.lang.Atom 0x71652c98 {:status :ready, :val 1}] #object[clojure.lang.Atom 0x1a1d3c1a {:status :ready, :val 2}])
user=> (reset! (nth a 0) 3)
3
user=> a
(#object[clojure.lang.Atom 0x71652c98 {:status :ready, :val 3}] #object[clojure.lang.Atom 0x1a1d3c1a {:status :ready, :val 2}])
'Programming' 카테고리의 다른 글
git fetch 와 git pull 의 차이 (0) | 2021.06.13 |
---|---|
비주얼스튜디오, 앱 실행 중에도 소스코드 수정·관리 (0) | 2021.05.29 |
(Free Pascal) TryStrToInt (0) | 2021.05.21 |
F# 파일 하나로 컴파일하기 (0) | 2021.05.19 |
F#을 스크립팅으로 쓰기는 어렵다. (0) | 2021.05.19 |