2010-04-04 3 views
5

데이터 구조에 여러 함수 호출을 미리 저장하고 나중에 다른 함수에서 평가/실행하고 싶습니다.Clojure에서 동적으로 바인딩 된 함수 실행

(함수 정의는 데이터 구조의 내 생성 후 오는에도 불구하고)하지만 let [name (fn 또는 함수 내에서 letfn에 의해 정의 된 기능을 작동하지 않습니다 defn와 네임 스페이스 수준에서 정의 된 기능 계획대로이 작동합니다.

가 여기 내 작은 자체에 포함 된 예제 :

경우
(def todoA '(funcA)) 
(def todoB '(funcB)) 
(def todoC '(funcC)) 
(def todoD '(funcD)) ; unused 

(defn funcA [] (println "hello funcA!")) 

(declare funcB funcC) 

(defn runit [] 
    (let [funcB (fn [] (println "hello funcB"))] 
    (letfn [(funcC [] (println "hello funcC!"))] 
     (funcA)  ; OK 
     (eval todoA) ; OK 
     (funcB)  ; OK 
     (eval todoB) ; "Unable to resolve symbol: funcB in this context" at line 2 
     (funcC)  ; OK 
     (eval todoC) ; "Unable to resolve symbol: funcC in this context" at line 3 
))) 

당신은 내가/OK (확인)의 주석 특정/실패 라인을 언급하는 6 개 문장의 결과를보고, 내 테스트 설정에 대해 궁금하고 REPL에서 (runit)으로 전화하십시오.

d 다른 함수 내부에서 정의 된 함수를 호출하는 간단한 함수가 있습니까?


업데이트 : (danlei의 제안에 따라)

작업을 수행합니다. 이 방법을 "실생활"에서 사용할 수 있는지 알아 봅시다.

(def todoB '(funcB)) 
(declare funcB) 

(defn runit [] 
    (binding [funcB (fn [] (println "hello funcB"))] 
    (funcB) 
    (eval todoB) ; "Unable to resolve symbol: funcB in this context" at line 1! 
)) 

업데이트 :

이 코드는 Constraint Satisfaction Problem 내 솔루션에 가고 - 나는 who owns the zebra을 찾고 싶어요! 나는 Clojure와 특히 함수 프로그래밍에 대해 상당히 익숙하다. 그리고 이것은 운동을 상당히 어렵게 만들었다. 나는 많은 구덩이에 빠졌지 만, 학습 경험의 일부이기 때문에 괜찮습니다.

나는 다음과 같이 간단한 벡터의 무리와 제약 조건을 지정하는 데 사용 :

[:con-eq :spain :dog] 
[:abs-pos :norway 1] 
[:con-eq :kools :yellow] 
[:next-to :chesterfields :fox] 

각 벡터의 첫 번째 제약 조건의 종류를 지정합니다 곳. 그러나 그 규칙에 대한 디스패치 메커니즘의 어색한 실시를 알려준, 그래서 (인용) 함수 대신 호출로 내가 그들을 인코딩하기로 결정

'(coloc :japan :parliament) ; 10 
'(coloc :coffee :green) ; 12 
'(next-to :chesterfield :fox) ; 5 

그래서 난 간단한 eval로 구속 규칙을 전달할 수 있습니다. 이것은 훨씬 더 우아하고 "lisp-y"처럼 보입니다. 그러나 이러한 각 기능은 내 도메인 데이터 (vars)에 액세스해야하며이 데이터는 프로그램 실행과 함께 계속 변경됩니다. 추가 규칙을 도입하여 규칙을 어지럽히고 싶지 않았으므로 vars을 동적 범위 지정을 통해 eval 개의 기능에 사용할 수있게하려고했습니다.

이제 동적 범위 지정은 binding을 사용하여 수행 할 수 있지만 declare도 필요하다는 것을 알게되었습니다.

+1

당신이 뭔가를 구현하기 위해 노력하고 정말 타이어를 발로 나 있습니까? 후자의 경우, 나는 당신이 그런 디자인을 사용하도록 강요하려는 것을 알고 싶다. 얼핏보기에 지연이나 평범한 오래된 폐쇄가 트릭을 할 수있다. – cgrand

+0

@cgrand : 관심을 가져 주셔서 감사합니다. 내가하려고하는 것을 설명하기 위해 두 번째 업데이트를 추가했습니다. 그 동안 저를 위해 일하고 있습니다. 그러나 나는 더 나은 제안을하는 것이 확실합니다! –

+0

@cgrand : 내 게시물 [Constraint Satisfaction Problem] (http://stackoverflow.com/questions/2500504/constraint-satisfaction-problem)에는 이제 완벽한 해결책이 있습니다. 관심이 있다면 거기에서 '바인딩'을 볼 수 있습니다. 나는 아마추어적인 접근에 대한 건설적인 비판에 대해 매우 열려 있습니다. –

답변

5

다음과 같은 것이 있습니까?

(def foo '(bar)) 
(declare bar) 

(binding [bar (fn [] (println "hello bar"))] 
    (eval foo)) 

네, 문제는 여기에 줄 경우 평가는 어휘 환경에서 평가하지 않기 때문에이 작동하지 않습니다

(let [foo 1] 
    (eval 'foo)) 

. 당신은 vars를 사용하여 주위를 둘러 볼 수 있습니다 :

(declare foo) 

(binding [foo 1] 
    (eval 'foo)) 

Clojure는 CL과 비슷한 의미를 갖는 것으로 보입니다 (cf. CLHS :

현재 동적 환경과 null 어휘 환경에서 양식을 평가합니다.

+0

네, 작동하는 것 같습니다. Clojure에 정통한 사람들이 점점 늘어나고 있다는 것이 좋습니다. 감사! –

+0

반갑습니다. 나는 이것이 교육 목적을위한 것이라고 생각합니다. 그렇지 않으면 질문에 대한 cgrand의 의견을 고려하십시오. – danlei

3

나는 당신이 잘못된 문제를 해결하고 있다고 생각합니다. 함수형 언어에서 함수는 값이며 다른 값을 저장할 수있는 모든 것에 할당 할 수 있습니다. 지도. 네임 스페이스를 조작하거나 아무것도 평가하려고해서는 안됩니다. 이것은 펄이 아닙니다.

로컬 맵을 변경하려면이 같은 및 사용 ASSOC을 시도해보십시오

user=> (def fnmap {:funcA (fn [x] (inc x)), :funcB (fn [x] (* x 2))}) 
#'user/fnmap 
user=> ((:funcA fnmap) 10) 
11 
user=> ((:funcB fnmap) 10) 
20 
+0

감사합니다. 이것이 내가하고있는 일과 거의 똑같은 것인지 확인하게되어 기쁩니다. 내 작업 솔루션의 코딩은 [Constraint Satisfaction Problem] (http://stackoverflow.com/questions/2500504/constraint-satisfaction-problem) 게시물에서 확인할 수 있습니다. –