2010-03-21 3 views
16

변수의 이름 목록이 주어지면 해당 변수를 식으로 설정하려고합니다. Clojure에서 문자열로 명명 된 변수를 정의하는 방법은 무엇입니까?

나는이 시도 :

(doall (for [x ["a" "b" "c"]] (def (symbol x) 666))) 

을 ...하지만이 오류를 얻을 수

의 java.lang.Exception : 첫 번째 인수가 기호해야 수비력

수 누구든지이 일을 제대로 수행 할 수있는 방법을 보여 주시겠습니까? 귀하의 코멘트에 대한 응답으로

답변

30

Clojure에서의 "인턴"기능이 목적을위한 것입니다 :

(doseq [x ["a" "b" "c"]] 
    (intern *ns* (symbol x) 666)) 
+0

가장 간결하고 직관적 인 (가능한?) 대답. 나는 당신에게 눈금을줬고 sepp2k가 그것을 잃어 버리는 것에 대해 화를 내지 않기를 바란다. 감사! –

13
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666)))) 

는 :

여기에 포함 된 어떠한 매크로가 없습니다. eval은 목록을 취하여 해당 목록을 코드로 실행 한 결과를 코드로 반환하는 함수입니다. `와 ~는 부분 인용 목록을 만드는 지름길입니다.

은의`~

~ 다음 목록 인용하지 실행되어야한다 함수 호출 인 선행되지 않는 한 다음 목록의 내용이 인용되어야 의미한다.

그래서`(DEF ~ (심볼 X) 666) is the list containing the symbol DEF , followed by the result of executingfollowed by the number of the beast. I could as well have written 심볼 X (평가 (리스트 'DEF (심볼 X) (666)))'와 동일한 효과를 얻기 위해.

+0

어떻게 든 평가 관련이 답을 알고 있지만, ~ 구조에 대해 잊어 버렸습니다. –

+0

글쎄, whaddaya 알아, 그냥 작동합니다! 이것을 달성하기 위해 매크로 수준으로 떨어지는 것이 필요하다고 생각하지는 못했지만 이것을 "이해하지 못하는 내용의 요리 책"에 포함시켜 드리겠습니다. 고맙습니다! –

+2

@CarlSmotricz : 방금 코드에 대한 설명을 추가했습니다. 바라건대 당신은 이제 더 완전히 이해할 수 있기를 바랍니다. – sepp2k

6

Stuart Sierra의 의견 (clojure.core/intern 언급)을 고려하여 업데이트되었습니다.

여기에 eval을 사용하면 괜찮 았지만 Vars가 이미 존재하는지 여부에 관계없이 필요하지 않다는 것을 아는 것은 흥미로울 수 있습니다. 사실, 그들이 존재하는 것으로 알려져 있다면, 나는 아래의 alter-var-root 솔루션이 더 깨끗하다고 ​​생각합니다; 그것들이 존재하지 않는다면, 나는 대안적인 제안을 훨씬 더 깨끗하게 주장하지 않을 것이지만, 가장 짧은 코드 (함수 정의를 위해 3 줄의 오버 헤드를 무시한다면)를 게시하는 것처럼 보인다. 그래서 나는 단지 포스트 할 것이다. 그것을 고려하십시오.


var에 존재하는 것으로 알려져 경우

(alter-var-root (resolve (symbol "foo")) (constantly new-value)) 

그래서 당신이 할 수있는 동일한 값이 모든 바르에 사용되는 있었다면

(dorun 
    (map #(-> %1 symbol resolve (alter-var-root %2)) 
     ["x" "y" "z"] 
     [value-for-x value-for-y value-for z])) 

(당신이 (repeat value)을 사용할 수 있습니다 마지막 인수를 매핑하거나 그냥 익명 함수에 넣으십시오.바르가 생성해야 할 수 있습니다)


, 당신은 실제로 나는 반드시이 eval 청소기보다라고 주장하지만, 어쨌든 않을 것이다, 다시 한번 (이 작업을 수행하는 함수를 작성할 수 있습니다 - 단지에 대한 그것의 관심) : var에가 밝혀지면 이미 주어진 네임 스페이스에 지정된 이름에 구금 된 것을

(defn create-var 
    ;; I used clojure.lang.Var/intern in the original answer, 
    ;; but as Stuart Sierra has pointed out in a comment, 
    ;; a Clojure built-in is available to accomplish the same 
    ;; thing 
    ([sym] (intern *ns* sym)) 
    ([sym val] (intern *ns* sym val))) 

주, 다음이 하나의 인수 경우 아무것도 변경하거나 단지에 바르 재설정 두 가지 주장에 새로운 가치가 주어진다. 목록의 모든 항목을 평가할 수있는 일반 함수 호출에 대한

user> (create-var 'bar (fn [_] :bar)) 
#'user/bar 
user> (bar :foo) 
:bar 

user> (create-var 'baz) 
#'user/baz 
user> baz 
; Evaluation aborted. ; java.lang.IllegalStateException: 
         ; Var user/baz is unbound. 
         ; It does exist, though! 

;; if you really wanted to do things like this, you'd 
;; actually use the clojure.contrib.with-ns/with-ns macro 
user> (binding [*ns* (the-ns 'quux)] 
     (create-var 'foobar 5)) 
#'quux/foobar 
user> quux/foobar 
5 
+0

매우 유익하고 매우 유익한, 매우 고맙습니다! 언뜻보기에 이것은'def'에 대한 코드가하는 일을하는 것처럼 보입니다. 나는 그것이 "갈래 인"'def'라고 생각합니다. 나는 다음 미니 프로젝트에서 이것을 사용할지도 모른다. –

+1

엄지 손가락의 규칙으로 : 당신이하고있는 것을 알기 전까지는 eval을 사용하지 마십시오. 나는 인턴과 함께 문제의 해결을 위해 갈 것이다. 이 대답은 eval이 여기에 필요 없다는 것을 멋지게 보여주었습니다. – danlei

+2

Var.intern은 빌트인 Clojure 함수 "intern"로 사용 가능합니다 –

3

평가 규칙, 첫 번째 전화 :

(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"])) 

일부 추가 예 : 이와 함께, 당신과 같이 원래의 문제를 해결할 수 항목을 함수로 사용하여 목록의 나머지 항목을 매개 변수로 사용합니다.

그러나 특수 폼이나 매크로에 대한 평가 규칙에 대한 가정은 할 수 없습니다. 특별한 형식이나 매크로 호출에 의해 생성 된 코드는 모든 인수를 평가하거나 평가하지 않거나 여러 번 평가하거나 인수를 평가할 수 있습니다. def은 특별한 형식이며 첫 번째 인수를 평가하지 않습니다. 그렇게했다면 작동하지 않을 수 있습니다. foo(def foo 123)으로 평가하면 대부분 "(예 : foo이 이미 정의 된 경우 사용자가 직접 정의하지 않을 경우)"그런 var 'foo'오류가 발생합니다.

나는 이것을 사용하고 있는지 확실하지 않지만 매우 관용적 인 것처럼 보이지 않습니다. def을 사용하면 프로그램의 최상위 레벨을 제외하고 일반적으로 뭔가 잘못하고 있다는 것을 의미합니다.

(참고 :. doall + for = doseq)

+0

'doseq'에 대해 상기시켜 주셔서 감사합니다! 나는 최상위 레벨에서 몇 가지 변수를 정의하고 타이핑을 줄이려고했다. –

+2

왜 문자열 대신에 기호를 사용하여 시작하십시오. –

+0

내가 사용할 계획이었던 이름이 자체적으로 계산 되었기 때문에 (병합, 내치에 의해).필자는 실험적이고 "빠르고 더러운"코드의 목적으로 만이 작업을 수행한다고 강조합니다. 내가하는 일을 표현하는 훨씬 더 좋은 방법이있다. 나는 초기 초안 코드에서이를 수행하기를 원했기 때문에이 질문을 올렸지 만 다른 뛰어난 Clojure 언어가이 특별한 jiggerpokery를 지원하지 않는 것처럼 보였습니다. –

관련 문제