2010-08-08 19 views
7

Nếu tôi làm như sau trong clojureChức năng clojure có phụ thuộc theo chu kỳ cụ thể không được phép theo thiết kế hay chỉ là hành vi của người đọc?

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (sub1b (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (sub1a (- a 1)))) 

(println (sub1a 10)) 

tôi nhận được lỗi sau:

java.lang.Exception: Unable to resolve symbol: sub1b in this context 

Nhưng nếu tôi làm như sau:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (- a 1))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (- a 1))) 

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (sub1b (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (sub1a (- a 1)))) 

(println (sub1a 10)) 

Nó chỉ chạy tốt.

Đây có phải là do thiết kế hay chỉ là một chức năng của cách trình đọc Clojure hoạt động?

Trả lời

16

Bạn có thể làm

(declare sub1a sub1b) 

'tuyên bố' có nghĩa là đặc biệt để tạo ra một var không có ràng buộc để làm tờ khai phía trước.

Một bạn đã khai báo tên:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (sub1b (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (sub1a (- a 1)))) 

(println (sub1a 10)) 

Cũng cách idomatic để xác định tình trạng mặc định trong cond (ví clojure) đang sử dụng: mệnh đề else. Đây là một chút khác với Common Lisp sử dụng T (cho True). Vì vậy, mã trước của bạn có thể được viết lại là:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    :else (sub1b (- a 1)))) 

... 
3

Giải pháp đúng là được đăng bởi rkrishnan.

Đối với phần này của câu hỏi:

Is this by design, or just a function of the way the Clojure reader works?

Trên thực tế đây là không có gì để làm với người đọc Clojure - đó là bởi vì trình biên dịch giải quyết các ký hiệu để Vars ngay khi gặp họ (ở những vị trí mà họ sẽ cần "cuối cùng" để được giải quyết cho một Var, trái ngược với những nơi mà họ đặt tên người dân địa phương, được trích dẫn hoặc thông qua một hình thức đặc biệt hoặc một vĩ mô, tất nhiên). Điều này có ý nghĩa vì lý do hiệu quả: biết Var là một biểu tượng đề cập đến thời gian biên dịch làm cho nó có thể tạo mã không cần giải quyết ký hiệu khi chạy (nó vẫn thường cần tra cứu các giá trị của Vars chứ không phải Vars mình). Nếu bạn thực sự muốn, bạn có thể có những biểu tượng đang quyết tâm của bạn trong thời gian chạy:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    :else ((resolve 'sub1b) (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    :else ((resolve 'sub1a) (- a 1)))) 

(println (sub1a 10)) 

; prints 0 and returns nil 

này, tuy nhiên, gây ra một sự xuống cấp nhất định trong việc thực hiện được hầu như không bao giờ biện minh trong mã thực tế, do đó Clojure làm cho bạn được rõ ràng về nếu bạn thực sự hãy nghĩ đây là điều bạn muốn.

Các vấn đề liên quan