2012-04-08 32 views
5

Tôi rất mới để che giấu, và tôi đã không thực hiện một tấn lisp trước đây. Tôi có một chức năng có chứa những điều sau đây:clojure: cách thành ngữ của việc loại bỏ trùng lặp trong một "if"?

(defn chord 
    ([scale degree num_voices] 
    (if 
     (keyword? degree) 
      (take num_voices (take-nth 2 (cycle (invert scale (.indexOf scale degree))))) 
      (take num_voices (take-nth 2 (cycle (invert scale degree)))))) 

Rõ ràng, mã này là nghèo vì có hai chức năng gần như giống hệt nhau gọi đây là tối ưu, nơi sự khác biệt duy nhất là (.indexOf scale degree) vs degree.

Cách Clojure/Lisp để xóa trùng lặp mã này là gì? Tôi cảm thấy như nó nên liên quan đến một let, nhưng tôi không tích cực. Bất kỳ con trỏ chung khác liên quan đến khối mã này cũng được đánh giá cao.

Edit: Tôi đã tái yếu tố mã theo gợi ý andrew Cooke, chức năng bây giờ đọc:

(defn chord 
    ([scale degree num_voices] 
     (let [degree (if (keyword? degree) (.indexOf scale degree) degree)] 
      (take num_voices (take-nth 2 (cycle (invert scale degree)))) 
     ) 
    ) 

Nhờ tất cả những người đã trả lời một cách nhanh chóng.

+2

Ít nhất cho chung lisp (và tôi giả clojure cũng), hai dấu ngoặc đơn cuối cùng thường được đặt ở cuối dòng (take ...); với một trình soạn thảo tốt mà thụt lề mã lisp, thụt đầu dòng sẽ thay thế cho những gì bạn đang làm với hai dấu ngoặc đơn cuối cùng. –

Trả lời

6

tôi sẽ viết:

(defn chord [scale degree num_voices] 
    (let [degree (if (keyword? degree) (.indexOf scale degree) degree)] 
    (take num_voices (take-nth 2 (cycle (invert scale degree))))) 

không chắc chắn nó giúp - không có nguyên tắc chung, ngoại trừ sử dụng let. Ngoài ra, có lẽ những người khác sẽ không thích cách tôi đổ bóng giá trị với degree, nhưng ở đây tôi nghĩ rằng nó giúp hiển thị ý định.

chỉnh sửa: so với các câu trả lời khác, tôi đã rút ra giá trị. tôi thích điều này để nhúng bởi vì tôi tìm thấy một chuỗi dài các đánh giá nhúng khó đọc hơn. ymmv.

ps suy nghĩ thêm [sau vài ngày sau] nếu bạn đang sử dụng kiểu này ở nhiều nơi (trong đó tham số có thể là giá trị hoặc khóa kéo dữ liệu từ giá trị trước) thì tôi có thể xem xét viết macro để tự động hóa quá trình đó (tức là một cái gì đó tạo ra một fn với tự động tạo ra cho phép của mẫu ở trên). vấn đề chính là quyết định làm thế nào để chỉ ra paraneters được xử lý theo cách đó (và cũng có thể, tôi sẽ lo lắng về việc làm thế nào điều này có thể gây nhầm lẫn bất kỳ ide bạn đang sử dụng).

+0

cảm ơn andrew, điều này có vẻ dễ đọc nhất, cho mắt của tôi. –

6

if trả về một biểu hiện, vì vậy đảo ngược cấu trúc chức năng của bạn:

(defn chord 
    ([scale degree num_voices] 
    (take num_voices (take-nth 2 (cycle (invert scale (if (keyword? degree) 
                   (.indexOf scale degree) 
                  (invert scale degree)))))))) 

Nó có lẽ sẽ tốt hơn nếu bạn sử dụng một let để nắm bắt kết quả của if.

+0

cảm ơn, upvoted, câu trả lời của bạn là tất nhiên chính xác nhưng "cho" làm cho nó một chút dễ đọc hơn tôi nghĩ. –

+0

@PaulSanwald Vâng, đó là lý do tại sao câu trả lời của tôi nói vậy. – Marcin

4

Trong Clojure (và hầu hết các lisps khác) if trả về một giá trị giống như mọi biểu thức khác. Ví dụ:

(if (even? 3) 1 0) 

đánh giá là 0.

Bạn có thể sử dụng kiến ​​thức này để cấu trúc lại mã của bạn bằng cách di chuyển các phần giống hệt nhau của mã bên ngoài của bản tuyên bố if, như vậy:

(defn chord [scale degree num-voices] 
    (take num-voices (take-nth 2 
          (cycle (invert scale 
              (if (keyword? degree) 
               (.indexOf scale degree) 
               degree)))))) 

Ngoài ra, trong Lisp, - không phải là đặc biệt hoặc dành riêng, vì vậy bạn có thể và nên sử dụng nó trong tên biến của bạn. Đó là phong cách lisp tốt hơn để sử dụng num-voices thay vì num_voices hoặc numVoices, vì tùy chọn đứt quãng được xem là dễ đọc hơn.

0

Có không nhiều mà có thể được thực hiện đơn giản hóa các thủ tục, có thể di chuyển if bên trong gọi đến take num_voices, như thế này:

(defn chord ([scale degree num_voices] 
    (take num_voices 
     (take-nth 2 
        (cycle (invert 
          scale 
          (if (keyword? degree) (.indexOf scale degree) degree))))))) 
Các vấn đề liên quan