2016-07-26 3 views
2

필자는 특수 함수 구조를 작성했습니다.이 구문은 실제로 Clojure 함수에 불과합니다. 따라서 기본적으로 (fn과 비슷한) 함수와 CL의 funcall과 비슷한 특수 함수를 호출하는 함수가 있습니다.컴파일시에 메타 데이터 값을 갖는 방법이 있습니까?

"내"함수와 다른/일반 Clojure 함수를 구별 할 수 있도록 내 생성자가 메타 데이터를 (컴파일 타임에) 할당합니다.

내가 원하는 것은 내 기능이 정상적인 기능인 것처럼 사용자가 코드를 작성할 수 있도록하는 것입니다. 그것은 코드를 걷는 것으로 그렇게 할 것이고, 함수 호출에서는 호출 수신자가 특수 함수 일 때 호출자를 사용할 수 있도록 호출을 변경할 것입니다 (그리고 추가 정보를 주입 할 수도 있습니다). 예 :

(defmacro my-fn [args-vector & body] ...) 
(defmacro my-funcall [myfn & args] ...) 
(defmacro with-my-fns [& body] ...) 

(with-my-fns 
    123 
    (first [1 2 3]) 
    ((my-fn [x y] (+ x y))) 10 20) 
; should yield: 
(do 
    123 
    (first [1 2 3]) 
    (my-funcall (my-fn [x y] (+ x y)) 10 20)) 

어휘 환경에서 문제가 발생합니다. 예를 들어 I 쓰려 매크로 (즉 with-my-fns)이 (myf) 발생하면이 경우

(with-my-fns 
    (let [myf (my-fn [x y] (+ x y))] 
    (myf)) 

, 그것은 상징 myf를보고하고, I는 메타 데이터에 액세스 할 수 없다. 그것은 또한 Var가 아니므로 resolve입니다.

그렇지 않으면 런타임에 거의 모든 단일 함수 호출에 대한 점검을해야하기 때문에 알 수 있습니다. 값에 대한 메타 데이터가 실제 Clojure 메타 데이터인지 여부는 신경 쓰지 않습니다. 타입 시스템과 이것 저것으로 가능하다면 그것도 좋을 것입니다.

P. 처음에 렉시 컬 환경에 대해 묻기를 원했지만 어쩌면 내 접근 방식이 실패하는 부분에 대해 알아야 할 함정이 더 많을 수도 있습니다. (또는 위의 내용은 실제로 XY 문제입니까? 제안을 환영합니다).

+0

, 당신은 객체 (기능) 런타임 메타 데이터를 연결하고 있습니다. 당연히 컴파일 타임에 런타임 객체의 메타 데이터에 접근 할 수 없다. (예 :'eval'uating하지 않고) – OlegTheCat

+0

@OlegTheCat 그래, 문제가있다. (iirc 실제 Clojure 메타 데이터는 어휘 환경에서 바운드 될 때를 제외하고는 효과가 있었지만). 메타 데이터 또는 다른 방법을 통해 컴파일 타임에이 데이터를 사용할 수있는 방법이 없습니까? – MasterMastic

+0

왜 myfun 매크로 안에 모든 마법을 넣지 않으시겠습니까? 왜 거기에 모든 수표를 추가 할 수 없습니까? – murphy

답변

1

@OlegTheCat가 이미 의견 섹션에서 지적했듯이 메타 데이터를 사용하는 아이디어는 효과가 없습니다. 난 당신이 함께 살 수있는 솔루션이있을 수 있습니다 그러나

:

(ns cl-myfn.core) 

(defprotocol MyCallable 
    (call [this magic args])) 


(extend-protocol MyCallable 
    ;; a clojure function implements IFn 
    ;; we use this knowledge to simply call it 
    ;; and ignore the magic 
    clojure.lang.IFn 
    (call [this _magic args] 
    (apply this args))) 

(deftype MyFun [myFun] 
    MyCallable 
    ;; this is our magic type 
    ;; for now it only adds the magic as first argument 
    ;; you may add all the checks here 
    (call [this magic args] 
    (apply (.myFun this) magic args))) 

;;turn this into a macro if you want more syntactic sugar 
(defn make-myfun [fun] 
    (MyFun. fun)) 

(defmacro with-myfuns [magic & funs] 
    `(do [email protected](map (fn [f#] 
       ;; if f# is a sequence it is treated as a function call     
       (if (seq? f#) 
        (let [[fun# & args#] f#] 
        `(call ~fun# ~magic [[email protected]#])) 

        ;; if f# is nonsequential it is left alone 
        f#)) 
       funs))) 


(let [my-prn (make-myfun prn)] 
    (with-myfuns :a-kind-of-magic 
    123 
    [1 2 3] 
    (prn :hello) 
    (my-prn 123))) 


;; for your convenience: the macro-expansion 

(let [my-prn (make-myfun prn)] 
    (prn (macroexpand-1 '(with-myfuns :a-kind-of-magic 
         123 
         [1 2 3] 
         (prn :hello) 
         (my-prn 123))))) 

출력 :

지금까지 내가 이해로
:hello 
:a-kind-of-magic 123 
(do 123 [1 2 3] (cl-myfn.core/call prn :a-kind-of-magic [:hello]) (cl-myfn.core/call my-prn :a-kind-of-magic [123])) 
관련 문제