2013-02-09 34 views
9

Ví dụ về Clojure arity-quá tải trên các chức năng như sau (lấy từ cookbook):Clojure :: chức năng arity-quá tải gọi nhau

(defn argcount 
    ([] 0)        ; Zero arguments 
    ([x] 1)        ; One argument 
    ([ x & args] (inc (count args)))) ; List of arguments 

... sử dụng một hình thức mà không có vẻ cho phép các hàm có độ tinh khiết thấp hơn chỉ đơn giản gọi các hàm của arity cao hơn với một số giá trị mặc định (đó là một thành ngữ phổ biến trong Java). Có phải một số hình thức đặc biệt khác được sử dụng cho điều đó không?

+3

Có hai cách để làm điều này, và câu hỏi này đã được trả lời trên StackOverflow. Đặc biệt chú ý đến câu trả lời thứ hai, sau này: http://stackoverflow.com/a/8660833/152739 – Scott

+0

Dường như làm việc tốt cho tôi: user => (defn f ([] (f 1)) ([ x] x)) # 'người dùng/f người dùng => (f) 1 –

Trả lời

13

Thường có cách tốt để biểu thị các đối số có độ cao cao hơn theo cách không cần tham chiếu đến các vị trí khác bằng các hàm bậc cao hơn và map/reduce. Trong trường hợp này nó khá đơn giản:

(defn argcount 
    ([] 0) 
    ([x] 1) 
    ([x & args] 
    (reduce + 1 (map (constantly 1) args)))) 

Thông báo dạng tổng quát của biểu thức là:

(reduce reducing-function arity-1-value (map mapping-function rest-of-args)) 

Bạn không thể làm tất cả mọi thứ theo cách này, nhưng hoạt động này cho một tỷ lệ đáng ngạc nhiên lớn của đa chức năng đối số. Nó cũng đạt các advnatages của sự lười biếng sử dụng map, vì vậy bạn có thể làm những việc điên rồ như vượt qua mười triệu đối số cho hàm với chút sợ hãi:

(apply argcount (take 10000000 (range))) 
=> 10000000 

Hãy thử rằng trong hầu hết các ngôn ngữ khác và chồng của bạn sẽ được bánh mì nướng :-)

3

Câu trả lời của mikera thật tuyệt vời; Tôi chỉ cần thêm một phương pháp bổ sung. Khi một giá trị mặc định là cần thiết cho một chức năng quá tải, một địa phương có thể được sử dụng.

Trong phân chia mẫu bên dưới, địa phương yêu cầu số và độ chính xác. Hàm được định nghĩa quá tải độ chính xác với một giá trị mặc định.

(def overloaded-division 
(let [divide-with-precision 
    (fn [divisor dividend precision] 
    (with-precision precision (/ (bigdec divisor) (bigdec dividend))))] 
    (fn 
     ;lower-arity calls higher with a default precision. 
     ([divisor dividend] (divide-with-precision divisor dividend 10)) 
     ;if precision is supplied it is used. 
     ([divisor dividend precision] (divide-with-precision divisor dividend precision))) 
    ) 
) 

Khi được gọi vào-arity thấp hơn, mặc định nó áp dụng:

user=> (overloaded-division 3 7) 
0.4285714286M 
user=> (overloaded-division 3 7 40) 
0.4285714285714285714285714285714285714286M 
Các vấn đề liên quan