2017-05-13 1 views
0

가 원래 다음과 같은 질문에 의해 동기 : Mapped calls to clojurescript macro매크로없이 Clojure`defn` 함수를 자동 생성하는 방법은 무엇입니까?


가 자동으로 많은 유사한 기능을 만들려는 가정 (즉없이 그들 모두를 손으로 작성). 우리는 몇 가지 기존 기능이 있다고 가정하고 우리는 어떤 종류의 콜백 핸들러로 포장합니다 : 결과

(defn do-foo [] (println "I foo'ed")) 
(defn do-bar [] (println "I bar'ed")) 
(defn do-baz [] (println "I baz'ed")) 

(defn manual-on-foo [] (do-foo)) 
(defn manual-on-bar [] (do-bar)) 
(defn manual-on-baz [] (do-baz)) 

(println "Calling manual-on-* functions") 
(manual-on-foo) 
(manual-on-bar) 
(manual-on-baz) 

:

Calling manual-on-* functions 
I foo'ed 
I bar'ed 
I baz'ed 

우리는 래퍼 함수를 ​​생성 할 자동이 아닌 수동으로 .

이 기능을 만들려면 매크로가 필요하다고 생각할 수도 있습니다. 그 해결책 중 하나입니다. 그러나 매크로의 약점은 다른 함수에 인수로 전달할 수 없다는 것입니다 (예 : map). 따라서, 우리는 같은 매크로를 작성할 수

(generate-fn :foo) ;=> creates `on-foo` w/o hand-writing it 

을하지만, 다음은 실패 :

(map generate-fn [:foo :bar :baz]) 

우리가 어떻게 이러한 기능의 생성을 자동화 할 수 있습니다? 매크로와 map을 사용할 수는 없지만

답변

2

개요

, 당신은이 기능을 수행하는 두 번째 매크로를 작성할 수 있습니다. 이것은 차례로, Clojure for the Brave and True 및 다른 장소에 설명 된 "Macros All Way Way"구의 근원 인 세 번째 매크로 등을 작성해야 할 수 있습니다.

비슷한 질문 was answered here을 Clojure의 intern 기능을 사용하여.

  • def 또는
  • defnvar-get
  • 를 사용하여 글로벌 VAR의 값에 액세스 할 수와 같은 글로벌 VAR을 만들려면 : 우리는 두 가지 방법으로 intern를 사용하여 여기에 있기 때문에 우리의 문제는 그 질문보다 조금 다르다 intern를 사용

기능 솔루션

은 우리가 자동으로 on-*를 functi를 생성하기 위해 다음과 같은 코드를 작성 할 수 있습니다 결과

(defn generate-onstar-f 
    [event-kw] 
    (let [ 
    event-str (name event-kw) 
    do-fn-sym (symbol (str "do-" event-str)) 
    on-fn-sym (symbol (str "on-" event-str)) 
    new-fn (fn on-fn-sym [] 
       (let [the-var (intern 'tst.clj.core do-fn-sym) ; get the var the symbol 'do-fn-sym' points to 
         the-fn (var-get the-var) ] ; get the fn the var is pointing to 
        (the-fn))) ] 
    (intern 'tst.clj.core on-fn-sym new-fn) ; create a var 'on-fn-sym' pointing to 'new-fn' 
    (println "Created" on-fn-sym))) 

(println \newline "*** generating functions ***") 
(mapv generate-onstar-f [:foo :bar :baz]) ; creates and interns a functions: my-foo, my-bar, my-baz 

(println \newline "Calling automatically generated on-* functions") 
(on-foo) 
(on-bar) 
(on-baz) 

: 기능 매크로를 사용하지 않고

*** generating functions *** 
Created on-foo 
Created on-bar 
Created on-baz 

Calling automatically generated on-* functions 
I foo'ed 
I bar'ed 
I baz'ed 

그래서 우리는 우리가 기능 on-foo을 만들어 볼 on-bar & on-baz 차례로, 글로벌 do-foo, do-bar, & do-baz 함수를 호출하는, . 그리고 우리는 매크로를 사용할 필요가 없었습니다!

Clojure에서 var는 on-foo과 같은 기호와이 기호가 가리키는 값 (이 예제의 함수) 사이의 보이지 않는 "중간 인물"입니다.자세한 내용은 게시물과 관련된 참조하십시오

When to use a Var instead of a function?


매크로 솔루션

앞서 언급 한 바와 같이, 하나가 다른 매크로를 호출하는 매크로를 사용할 수 있습니다, 사이드 스텝 문제를 그 매크로 수 ' map과 같은 고차 함수 (HOF)와 함께 사용하십시오. 결과

(defmacro generate-onstar-m 
    [event-kw] 
    (let [event-str (name event-kw) 
     do-fn-sym (symbol (str "do-" event-str)) 
     on-fn-sym (symbol (str "on-" event-str "-m"))] 
    (println "Creating" on-fn-sym) 
    `(defn ~on-fn-sym [] 
     (~do-fn-sym)))) 

(println \newline "Using Macro") 
(generate-onstar-m :foo) 
(on-foo-m) 

(defmacro run-macro 
    "Run the specified macro once for each arg" 
    [root-macro args] 
    `(do 
    [email protected](forv [item args] 
     `(~root-macro ~item)))) 

(println \newline "Generating on-*-m functions using `run-macro`") 
(run-macro generate-onstar-m [:foo :bar :baz]) 
(on-foo-m) 
(on-bar-m) 
(on-baz-m) 

:

Using Macro 
Creating on-foo-m 
I foo'ed 

Generating on-*-m functions using `run-macro` 
Creating on-foo-m 
Creating on-bar-m 
Creating on-baz-m 
I foo'ed 
I bar'ed 
I baz'ed 
여기에 우리가 새 매크로 run-macro 정의, 우리가 generate-onstar-f와 함께 사용할 수 없습니다 map HOF를 대체하는
관련 문제