2012-03-27 30 views
11

Tất cả các ví dụ được lấy từ Sách SICP: http://sicpinclojure.com/?q=sicp/1-3-3-procedures-general-methodsCách tiêu chuẩn để viết các câu lệnh xác định lồng nhau (như trong sơ đồ) cho clojure là gì?

này được thúc đẩy từ loạt video MIT về LISP - http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/2a-higher-order-procedures/

Trong chương trình, bạn có thể đặt 'định nghĩa' bên trong một 'định nghĩa':

(define (close-enough? v1 v2) 
    (define tolerance 0.00001) 
    (< (abs (- v1 v2)) tolerance)) 

Trong clojure, đó là 'let' tuyên bố với sự khác biệt duy nhất mà nó được lồng:

(defn close-enough? [v1 v2] 
    (let [tolerance 0.00001] 
     (< (Math/abs (- v1 v2)) 
      tolerance))) 

Nhưng những gì về viết lại trong clojure một cái gì đó lớn hơn như thế này ?:

(define (sqrt x) 
    (define (fixed-point f first-guess) 
    (define (close-enough? v1 v2) 
     (define tolerance 0.00001) 
     (< (abs (- v1 v2)) tolerance)) 
    (define (try guess) 
     (let ((next (f guess))) 
     (if (close-enough? guess next) 
      next 
      (try next)))) 
    (try first-guess)) 
    (fixed-point (lambda (y) (average y (/ x y))) 
      1.0)) 

này làm trong công việc thực tế nhưng trông rất độc đáo ...

(defn sqrt [n] 
    (let [precision  10e-6 
     abs    #(if (< % 0) (- %) %) 
     close-enough? #(-> (- %1 %2) abs (< precision)) 
     averaged-func #(/ (+ (/ n %) %) 2) 
     fixed-point  (fn [f start] 
          (loop [old start 
            new (f start)] 
           (if (close-enough? old new) 
            new 
            (recur new (f new)))))] 

     (fixed-point averaged-func 1))) 

(sqrt 10) 

UPDATED Mar/8/2012

Cảm ơn câu trả lời!

Về cơ bản 'letfn' không quá khác biệt với 'let' - các hàm được gọi phải được lồng trong định nghĩa 'letfn' (trái ngược với Đề án trong đó các hàm được sử dụng trong sexp tiếp theo sau định nghĩa của nó và chỉ tồn tại trong phạm vi của hàm cấp cao nhất mà nó được xác định).

Vì vậy, một câu hỏi khác ... Tại sao không clojure cung cấp cho khả năng làm những gì chương trình nào? Có một số loại quyết định thiết kế ngôn ngữ không? Những gì tôi thích về việc tổ chức chương trình là:

  • 1) Các đóng gói các ý tưởng vì vậy mà tôi như các lập trình viên có một ý tưởng như những gì các khối nhỏ đang được sử dụng khối lớn - đặc biệt là nếu tôi chỉ sử dụng ít khối một lần trong khối lớn (vì lý do gì, ngay cả khi các khối nhỏ hữu ích trong quyền riêng của họ).

  • 2) Điều này cũng dừng gây ô nhiễm không gian tên với ít thủ tục không hữu ích cho người dùng cuối (tôi đã viết chương trình clojure, quay lại sau một tuần và phải tìm hiểu lại mã của tôi vì nó trong một cấu trúc phẳng và tôi cảm thấy rằng tôi đã nhìn vào mã bên trong ra ngoài như trái ngược với một cách từ trên xuống).

  • 3) Giao diện định nghĩa phương pháp chung để tôi có thể rút ra một phương thức phụ cụ thể, bỏ thụt lề thử nghiệm và dán lại phiên bản đã thay đổi mà không quá khó sử dụng.

Tại sao điều này không được thực hiện trong clojure?

+1

đó là một câu hỏi thú vị nhưng tôi không nghĩ rằng tôi sẽ cố gắng đặt tất cả trong một chức năng. – Kevin

Trả lời

15

cách tiêu chuẩn để viết lồng nhau, được đặt tên, thủ tục trong clojure là sử dụng letfn.

như một sang một bên, việc sử dụng ví dụ của bạn về hàm lồng nhau là khá đáng ngờ. tất cả các hàm trong ví dụ có thể là các hàm không phải cục bộ ở mức cao nhất vì chúng ít nhiều hữu dụng và không đóng bất kỳ thứ gì ngoài nhau.

+0

Cảm ơn bạn! Vui lòng xem câu hỏi được cập nhật! – zcaudate

11

Những người phê bình vị trí của ông về điều này trong tất cả một chức năng, không hiểu bối cảnh tại sao nó được thực hiện theo cách như vậy.SICP, là ví dụ từ, đã cố gắng minh họa khái niệm về một mô-đun, nhưng không thêm bất kỳ cấu trúc nào khác vào ngôn ngữ cơ bản. Vì vậy, "sqrt" là một mô-đun, với một chức năng trong giao diện của nó, và phần còn lại là các hàm cục bộ hoặc riêng trong mô-đun đó. Điều này được dựa trên lược đồ R5RS tôi tin, và các đề án sau đó đã thêm vào một cấu trúc mô-đun chuẩn mà tôi nghĩ (?). Nhưng bất kể, nó thể hiện rõ hơn nguyên tắc che giấu việc thực hiện.

Trình lược đồ dày dạn cũng đi qua các ví dụ tương tự về các hàm cục bộ lồng nhau, nhưng thường là để ẩn cả triển khai và đóng các giá trị. Nhưng ngay cả khi đây không phải là một ví dụ sư phạm, bạn có thể thấy đây là một mô-đun rất nhẹ và tôi có thể viết nó theo cách này trong một mô-đun "thực" lớn hơn. Tái sử dụng là ok, nếu kế hoạch của nó cho. Nếu không, bạn chỉ cần phơi bày các chức năng có thể sẽ không hoàn toàn phù hợp với những gì bạn cần sau này, và đồng thời, gánh nặng các chức năng đó với các trường hợp sử dụng bất ngờ có thể làm hỏng chúng sau này.

4

letfn là cách tiêu chuẩn.

Nhưng vì Clojure là một Lisp, bạn có thể tạo (gần như) bất kỳ ngữ nghĩa nào bạn muốn. Dưới đây là bằng chứng về khái niệm xác định define theo điều khoản của letfn.

(defmacro define [& form] 
    (letfn [(define? [exp] 
      (and (list? exp) (= (first exp) 'define))) 
      (transform-define [[_ name args & exps]] 
      `(~name ~args 
       (letfn [[email protected](map transform-define (filter define? exps))] 
       [email protected](filter #(not (define? %)) exps))))] 
    `(defn [email protected](transform-define `(define [email protected]))))) 

(define sqrt [x] 
    (define average [a b] (/ (+ a b) 2)) 
    (define fixed-point [f first-guess] 
    (define close-enough? [v1 v2] 
     (let [tolerance 0.00001] 
     (< (Math/abs (- v1 v2)) tolerance))) 
    (define tryy [guess] 
     (let [next (f guess)] 
     (if (close-enough? guess next) 
      next 
      (tryy next)))) 
    (tryy first-guess)) 
    (fixed-point (fn [y] (average y (/ x y))) 
       1.0)) 

(sqrt 10) ; => 3.162277660168379 

Đối với mã thực tế, bạn muốn thay đổi define cư xử giống như R5RS: cho phép các giá trị phi fn, có sẵn trong defn, defmacro, let, letfnfn, và xác minh rằng các định nghĩa bên trong là lúc bắt đầu của cơ thể kèm theo.

Lưu ý: Tôi phải đổi tên try thành tryy. Rõ ràng try là một cấu trúc non-function, non-macro đặc biệt mà định nghĩa lại âm thầm không thành công.

+0

Điều đó rất hay. Tôi ước tôi có thể đưa ra câu trả lời của bạn nhiều hơn! – zcaudate

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