2011-05-08 8 views
1

기본적으로 저는 매크로가 처음인데 Clojure에서 매크로를 작성하는 방법을 알아 내려고합니다. 문제는 계속 예외 오류가 발생하고 어디서 처리해야하는지 파악하기가 매우 어렵습니다. 그래서 정말로 내가 궁금해하는 점은 Clojure 매크로를 디버깅하기위한 방법 (또는 경험적 방법) 목록을 얻을 수 있는지 여부입니다. Clojure에서 일반적인 매크로 오류를 해결하는 방법

내가 작업하고있는 현재의 문제를 가지고, 나는이 모델이 있습니다

{:users [:name :email :registered-on] 
:post [:title :author]} 

을 나는 형태로 변환 할 :

나는이 매크로를 쓴하는
(do (def new-form-users (cashew.core/new-form "https://stackoverflow.com/users/new" "Create a new Users" 
     ["name" "email" "registered-on"] ("Name" "Email" "Registered-on"))) 
    (def new-form-post (cashew.core/new-form "/post/new" "Create a new Post" 
     ["title" "author"] ("Title" "Author")))) 

: 내가 매크로를 실행할 때

(defmacro gen-create-forms [model] 
       `(do 
       [email protected](for [[entity-kw values] model] 
         (let [entity-sym (-> entity-kw name capitalize) 
          fields (vec (map name values))] 
          `(def ~(symbol (str "new-form-" (name entity-kw))) (new-form ~(str "/" (name entity-kw) "/new") ~(str "Create a new " entity-sym) ~fields ~(map capitalize fields))))))) 

그러나 내가 얻을 :

,536,
java.lang.String cannot be cast to clojure.lang.IFn 
    [Thrown class java.lang.ClassCastException] 

나는 macroexpand-1을 호출 해 보았습니다.하지만 해결 방법에 대해서는 거의 생각 나지 않은 채 같은 오류가 발생합니다.

This tutorial provided by John Lawrence Aspden "컴파일러가 일부 코드를 반환하는 함수 인 매크로를 보게되면 함수를 실행하고 반환 된 코드를 프로그램으로 대체합니다." 필자가 가지고있는 값을 받아들이고 결과를 변환하려는 함수로 매크로를 작성하도록했습니다.

는 따라서이 작품 :

(defn gen-create-forms [model] 
       `(do 
       [email protected](for [[entity-kw values] model] 
         (let [entity-sym (-> entity-kw name capitalize) 
          fields (vec (map name values))] 
          `(def ~(symbol (str "new-form-" (name entity-kw))) (new-form ~(str "/" (name entity-kw) "/new") ~(str "Create a new " entity-sym) ~fields ~(map capitalize fields))))))) 

(gen-create-forms {:users [:name :email :registered-on] 
       :post [:title :author]}) 
(do (def new-form-users (cashew.core/new-form "https://stackoverflow.com/users/new" "Create a new Users" ["name" "email" "registered-on"] ("Name" "Email" "Registered-on"))) (def new-form-post (cashew.core/new-form "/post/new" "Create a new Post" ["title" "author"] ("Title" "Author")))) 

내가 제대로 여기에 매크로를 사용하고 있는지 확실하지 않습니다 또는 매크로는이 문제를 해결하기위한 올바른 전략을 경우. 그러나 매크로를 작성하거나 예외를 디버깅 할 때 예외가 발생할 때 어떤 작업을하는지에 대한 아이디어는 많이 감사 할 것입니다.

EDIT : mikera는 이것이 좋은 예는 아니지만 제 질문은 여전히 ​​유효합니다. 따라서 을 반복하기 위해 clojure에서 매크로를 코딩하는 경우 예외가 발생했을 때 어떤 기술을 사용합니까?

답변

2

개인적으로 나는이에 대한 매크로를 사용하지 것이다 - 내 제안 된 대안은 다음과 같습니다

  • 피 네임 스페이스에서 새 심볼 이름을 생성하려고 -이 지저분하고 복잡한 얻을 수 있습니다!
  • 대신 해시 맵의 모든 양식을 포함하는 "new-forms"라는 단일 데이터 구조를 만드십시오. 키워드 나 문자열을 키로 사용할 수 있습니다. 개인적으로는 모델 데이터 구조에 이미이 방법을 사용하고 있으므로 ": users"와 같은 키워드를 사용합니다.
  • , 당신은 그럼 그냥 (new-forms :users) 또는 유사한을
  • 특정 양식을 ACESS 할
  • 을 할 수있는 필요에 따라 모델에서 각 양식에 대한 (cashew.core/new-form ...)을 매개 변수로 모델을 소요하고 호출하는 기능을 가진 "새로운 형태의"생성 해시 맵에서 적절한 양식을 읽습니다.
+0

그래서 정의하고있는 모든 기능을 포함하는 중첩 된 데이터 구조가 있습니까? 예 : (newform : users {: new # : read # } : 게시물 {: 새 # : # })이 차이점은 무엇입니까/생성 된 양식에 대한 새로운 네임 스페이스를 만드는 것만으로 얻을 수있는 이점은 무엇입니까? 그러나 나는 끔찍한 예제를 사용했다는 점을 인정할 것이다. 그러나 그것은 여전히 ​​나의 질문에 답하지 않는다. 그렇게 많이 생각하지 않아도, 이것은 여전히 ​​유용합니다! – toofarsideways

+1

예 - 중첩 된 데이터 구조가 가장 적합하다고 생각합니다. 필자는 "수동으로 소스 코드에서 정의한"것에 대해서만 네임 스페이스를 사용하는 경향이 있습니다. 그래서 프로그래밍으로 생성/생성하는 모든 것들은 일반적으로 데이터 구조에 넣을 것입니다. 이것은 단지 개인적인 취향이다. (네임 스페이스는 실제적으로 일종의 맵이다.)하지만 네임 스페이스에 혼동, 유지 보수 문제 및 충돌 가능성을 피하는 것이 도움이된다고 생각한다. – mikera

+0

당신은 @mikera를 알고 있습니다. 저는이 의견을 정말로 감사하기 시작했습니다. 그 아이디어에 대해 감사드립니다. – toofarsideways

관련 문제