2008-11-22 30 views
5

Tôi đang học lập trình chức năng và đã cố gắng giải quyết một vài vấn đề theo kiểu chức năng. Một điều tôi gặp phải, trong khi phân chia vấn đề của mình thành các hàm, có vẻ như tôi có hai lựa chọn: sử dụng một số hàm khác nhau với các danh sách tham số tương tự, hoặc sử dụng các hàm lồng nhau, như các bao đóng, có thể chỉ đơn giản tham chiếu đến các ràng buộc trong hàm cha.Chức năng lồng nhau: Sử dụng các tác dụng phụ không đúng cách?

Mặc dù tôi đã kết thúc với cách tiếp cận thứ hai, vì nó thực hiện các cuộc gọi hàm nhỏ hơn và dường như "cảm thấy" tốt hơn, từ đọc sách của tôi có vẻ như tôi đang thiếu một trong những điểm chính của lập trình hàm, điều này có vẻ "tác dụng phụ"? Bây giờ được cấp, các hàm lồng nhau này không thể sửa đổi các ràng buộc bên ngoài, vì ngôn ngữ tôi đang sử dụng ngăn cản điều đó, nhưng nếu bạn nhìn vào từng hàm bên trong riêng lẻ, bạn không thể nói "cho cùng một tham số, hàm này sẽ trả về cùng một kết quả" bởi vì họ sử dụng các biến từ phạm vi phụ huynh ... tôi có đúng không?

Cách mong muốn để tiến hành là gì?

Cảm ơn!

Trả lời

2

Chức năng lồng nhau là một cách tuyệt vời để phân chia lao động theo nhiều chức năng. Nó không thực sự "tác dụng phụ"; nếu nó giúp, hãy suy nghĩ về các biến bị bắt như các tham số ngầm định.

Một ví dụ trong đó hàm lồng nhau hữu ích là thay thế vòng lặp. Các tham số cho hàm lồng nhau có thể hoạt động như các biến cảm ứng tích lũy các giá trị. Một ví dụ đơn giản:

let factorial n = 
    let rec facHelper p n = 
     if n = 1 then p else facHelper (p*n) (n-1) 
    in 
    facHelper 1 n 

Trong trường hợp này, nó sẽ không thực sự có ý nghĩa với tuyên bố một chức năng như facHelper trên toàn cầu, vì người dùng không cần phải lo lắng về các tham số p.

Xin lưu ý, tuy nhiên, có thể khó kiểm tra các hàm lồng nhau riêng lẻ, vì chúng không thể được giới thiệu bên ngoài cha mẹ của chúng.

+0

facHelper không thực sự đề cập đến bất kỳ giá trị bên ngoài nào - nó vẫn hoàn toàn hoạt động. –

3

Lập trình chức năng không phải là tất cả hoặc không có gì. Nếu lồng các hàm có ý nghĩa hơn, tôi sẽ đi theo cách tiếp cận đó. Tuy nhiên, nếu bạn thực sự muốn các hàm bên trong hoàn toàn hoạt động, hãy chuyển tất cả các tham số cần thiết vào chúng một cách rõ ràng.

Dưới đây là một ví dụ nhỏ trong Đề án:

(define (foo a) 
    (define (bar b) 
    (+ a b))  ; getting a from outer scope, not purely functional 
    (bar 3)) 

(define (foo a) 
    (define (bar a b) 
    (+ a b))  ; getting a from function parameters, purely functional 
    (bar a 3)) 


(define (bar a b) ; since this is purely functional, we can remove it from its 
    (+ a b))  ; environment and it still works 

(define (foo a) 
    (bar a 3)) 

Cá nhân, tôi muốn đi với cách tiếp cận đầu tiên, nhưng một trong hai sẽ làm việc tốt như nhau.

1

xem xét như sau (giả tạo) đoạn Haskell:

putLines :: [String] -> IO() 
putLines lines = putStr string 
    where string = concat lines 

string là một địa phương bị ràng buộc tên không đổi. Nhưng không phải nó cũng là một chức năng không có đối số nào đóng trên lines và do đó có tính tham chiếu không minh bạch? (Trong Haskell, hằng số và các hàm null thực sự không thể phân biệt được!) Bạn có xem xét đoạn mã trên “tác dụng phụ” hay không có chức năng vì điều này không?

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