2010-03-07 2 views
5

방금 ​​Clojure를 사용하기 시작했습니다. 몇 가지 기능을 이해할 수 있도록 작은 스크립트를 작성했습니다. 출력과 같이 Clojure의 "let"에 혼란 스럽군요

(def *exprs-to-test* [ 
    "(filter #(< % 3) '(1 2 3 4 3 2 1))" 
    "(remove #(< % 3) '(1 2 3 4 3 2 1))" 
    "(distinct '(1 2 3 4 3 2 1))" 
]) 

그런 다음이 *exprs-to-test*을 통해, 그들 모두를 평가 가고, 인쇄 : 그것은 다음과 같이 시작

(doseq [exstr *exprs-to-test*] 
    (do 
     (println "===" (first (read-string exstr)) "=========================") 
     (println "Code: " exstr) 
     (println "Eval: " (eval (read-string exstr))) 
    ) 
) 

위의 코드는 모든 작업 괜찮습니다.

(doseq [exstr *exprs-to-test*] 
    (let [ex (read-string exstr)] (
     (do 
      (println "===" (first ex) "=========================") 
      (println "Code: " exstr) 
      (println "Eval: " (eval ex)) 
     ) 
    )) 
) 

을하지만이 후, *exprs-to-test*의 첫 번째 항목에 대해 한 번 작동하는 NullPointerException와 충돌 그러나, (read-string exstr) 반복 그래서 난과 같이 반복을 제거하기 위해 let을 사용하려고했습니다. let이 추락 한 이유는 무엇입니까?

답변

7

do 폼 주변에 여분의 괄호 세트가 있습니다. (함수 호출로)을 실행하기 위해 전체 do 형태의 값을하려고

((do ...)) 

하지만 do 형태의 마지막 printlnnil을 반환하기 때문에 donil을 반환 : 코드는이 작업을하고있다.

참고로 들여 쓰기 스타일은 비표준입니다. 종결 괄호를 각자의 줄에 두어서는 안됩니다. 그리고 let은 내재적 인 do을 가지고 있으므로 필요하지 않습니다.

user> (doseq [exstr *exprs-to-test*] 
     (let [ex (read-string exstr)] 
      (println "===" (first ex) "=========================") 
      (println "Code: " exstr) 
      (println "Eval: " (eval ex)))) 
=== filter ========================= 
Code: (filter #(< % 3) '(1 2 3 4 3 2 1)) 
Eval: (1 2 2 1) 
=== remove ========================= 
Code: (remove #(< % 3) '(1 2 3 4 3 2 1)) 
Eval: (3 4 3) 
=== distinct ========================= 
Code: (distinct '(1 2 3 4 3 2 1)) 
Eval: (1 2 3 4) 
+0

그걸 수정했습니다. 들여 쓰기 스타일 팁도 주셔서 감사합니다. –

1

브라이언은 이미 당신의 질문에 대답, 그래서 난 그냥 당신에게 수 있도록 형식에 대한 몇 가지 일반적인 포인터주고 싶다 :이 시도

4

나는 다른 대답이 방안의 코끼리를 무시하고 있다고 생각한다. 왜 이러는거야? 학습 Clojure를 통해 내가 잘못된 길을 단조하는 걱정하게 코드에서 많은 일들이 있습니다 사용

  • 글로벌 바인딩 (exprs - 투 - 테스트) doseq /에 println에 사용
  • REPL 통해 Clojure에서의 API를 배울 평가

에게 가장 좋은 방법을 사용하여 순서

  • 에서 코드를보십시오. 텍스트 파일의 정적 코드와 대화식 REPL간에 쉽게 이동할 수 있도록 Vim, Emacs 또는 IDE와 같은 환경을 설정해야합니다. Here is a good breakdown of a number of Clojure IDEs.

    이제 코드가 간다면 기억해야 할 몇 가지 사항이 있습니다. 첫째, eval을 사용할 좋은 이유는 거의 없습니다. 자신이이 일을하는 것을 발견하면, 정말로 필요한지 스스로에게 물어보십시오. 둘째, Clojure는 함수형 언어이며 일반적으로 "do"매크로 세트를 사용할 필요가 없다는 것을 기억하십시오."do"매크로는 부작용이 필요할 때 유용합니다 (예를 들어 부작용은 println에서 out *까지입니다). 마지막으로 글로벌 변수를 사용하는 것도 피해야합니다. vars를 사용해야하는 경우 바인딩 매크로를 사용하여 vars를 스레드에 로컬로 바인드하여 변경 불가능한 값으로 지정하여 동시성 문제가 없는지 고려해야합니다.

    Clojure를 효과적으로 활용하기 위해 프로그래밍 방식을 바꾸는 데 필요한 변화를 진정으로 이해하려면 프로그래밍 Clojure 또는 LISP에 대한 더 깊은 참조를 가져 오는 것이 좋습니다. 여기서 작은 샘플을 사용하면 마치 Clojure에서 무언가를 작성하려고하는 것처럼 느껴진다. Clojure는 전혀 작동하지 않을 것이다.

  • +0

    전역 변수가이 10 줄 스크립트에서 제어 할 수 없다는 것을 알고 있으며 실제로 필요한 상황에서도 더 이상 "do"매크로와 평가판을 사용하지 않을 것입니다. REPL에 대한 조언도 듣겠습니다. 왜냐하면 제가 10 분 동안 사용해온 언어의 완벽한 기억을 가지고 있으며, 나중에 참조 할 수 있도록 작업을 저장할 필요가 없기 때문입니다. 노련한 Clojure 전문가로서 당신의 의로운 무응답이 수치 스럽습니다. 나는 다음 번에 열심히 노력할 것이다. –

    +0

    역겨운 snarky 및 냉소적 인 코멘트. 나는 도우려고 노력했다. 부끄러운 줄 알아. –

    +0

    초보자 용 코드가 완벽하지 않은 방법에 관한 질문과 걸레를 무시하는 것이 적절하다고 생각하지 않습니다. 도움을주는 것보다 나팔을 부는 것처럼 느껴졌습니다. –