Clojure macro 초급 딱지 떼기

목표

클로저 매크로를 할 일은 별로 없을 것 같고 보고 읽을 줄 아는 정도의 지식을 쌓자

알거라 생각하거나 알면 좋은 내용

사전 지식

사전 지식이라기 보다는 이 글 내내 반복해서 나오는 것들에 대해서 미리 요약해둔 것이라고 보면 된다. 이 글을 다 읽고도 아래 나열된 것들을 이해 못했다면 글쓴이의 잘못이다.

예제를 사전 지식을 가다듬자

예제는 Brave Clojure를 일부 참고했다.

평가된 + 심볼.

+
; => #function[clojure.core/+]

평가되지 않은 + 심볼.

'+
; +
(quote +)
; +

보통 클로저에서 사용하는 (함수 인자 인자) 표현식이다. 괄호 안의 표현이 평가되었다.

(+ 1 2)
; => 3

single quote를 사용해보자. 괄호 안의 표현이 평가되지 않았다.

'(+ 1 2)
; => (+ 1 2)

syntax quote를 사용해보자. + 함수의 네임스페이스를 포함한 심볼을 반환했다.

`(+ 1 2)
; => (clojure.core/+ 1 2)

조금 어색하지만 syntax quote를 하고도 ~를 이용해서 평가를 해보자.

`~(+ 1 2)
; => 3

생각해보자. 우리가 평소에 사용하는 방식이다. 쉽다.

(+ 1 (inc 1))
; => 3

이거는 어떻게 될까? 위에서 생각한대로 평가를 미룬다고 생각해보자. 괄호 안의 평가들이 다 미루어졌다.

`(+ 1 (inc 1))
; => (clojure.core/+ 1 (clojure.core/inc 1))

(inc 1)는 평가가 되었으면 한다. 그럼 이렇게 해보면 된다.

`(+ 1 ~(inc 1))
; => (clojure.core/+ 1 2)

이렇게 하면 어떻게 될까?

`(+ 1 (~inc 1))
; => (clojure.core/+ 1 (#function[clojure.core/inc] 1))
; inc만 평가되어 나왔다.

unquote slicing을 알아보자. 먼저 우리가 알던 것을 보자. 평가를 꺼뒀지만 두번째 괄호 안에서는 평가를 바로 하도록 ~를 썼다. list가 잘 반환되었다.

`(+ ~(list 1 2 3))
; => (clojure.core/+ (1 2 3))

망치로 바꿔보자. 이렇게 하면 unwrap된 상태이다.

`(+ ~@(list 1 2 3))
; => (clojure.core/+ 1 2 3)

gensym은 아래처럼 만든다.

(gensym foo)
; => foo7366

auto-gensym'd는 아래처럼 만든다. unquote 상태에서 #을 붙인다..

`foo#
; => foo__7368__auto__

이것처럼 활용할 수 있다.

`(let [my-symbol# 3]
    (...))

Reference

Discuss this post here.

Published: 2021-12-18

Tagged: Clojure Macro

Archive