2012-11-24 29 views
6

Khi tôi đang nghiên cứu Haskell, tôi hiểu nó là một ngôn ngữ thuần túy. Tôi gặp khó khăn khi hiểu tại sao let -báo cáo không vi phạm độ tinh khiết.Độ tinh khiết chức năng bằng cách sử dụng 'let' trong Haskell

Ví dụ (trong ghci):

Prelude> let e = exp 1 
Prelude> e 
2.718281828459045 
Prelude> let e = 2 
Prelude> e 
2 

không phải là thứ hai let tuyên bố của tôi tạo ra một tác dụng phụ? Hoặc là tuyên bố thứ hai let có một sự đóng mới?

+0

@jberryman 2) và 3) đã được đề cập trong nửa sau của [câu trả lời của tôi] (http://stackoverflow.com/questions/13545580/functional-purity-using-let-in-haskell/13545731#13545731) theo nhận xét tương tự của dbaupp dưới đây. – AndrewC

Trả lời

21

Số thứ hai let tạo một ràng buộc mới cho e làm bóng biến hiện tại. Nó không sửa đổi e. Bạn có thể dễ dàng kiểm tra này như sau:

Prelude> let e = 1 
Prelude> let f() = "e is now " ++ show e 
Prelude> f() 
"e is now 1" 
Prelude> let e = 2 
Prelude> e 
2 
Prelude> f() 
"e is now 1" 
Prelude> 
16

let giới thiệu một biến địa phương mới với một giá trị bất di bất dịch duy nhất, và nó có phạm vi địa phương hơn bất kỳ định nghĩa xung quanh, vì vậy ví dụ:

*Main> (let length = 2 in show length) ++ ' ':show (length "Hello") 
"2 5" 

Ở đây, length đầu tiên có giá trị 2, nhưng phạm vi của nó cục bộ cho dấu ngoặc vuông. Bên ngoài dấu ngoặc đơn, length có nghĩa là ý nghĩa của nó. Không có gì đã được chỉnh sửa, chỉ là một biến địa phương hơn đã được giới thiệu xảy ra có cùng tên với một biến khác trong một phạm vi khác. Hãy làm cho ghci điên bằng cách bỏ qua các dấu ngoặc và làm cho nó cố gắng làm cho length một số và một chức năng:

*Main> let length = 2 in show length ++ ' ':show (length "Hello") 

<interactive>:1:14: 
    No instance for (Num ([Char] -> a0)) 
     arising from the literal `2' 
    Possible fix: add an instance declaration for (Num ([Char] -> a0)) 
    In the expression: 2 
    In an equation for `length': length = 2 
    In the expression: 
     let length = 2 in show length ++ ' ' : show (length "Hello") 

<interactive>:1:19: 
    No instance for (Show ([Char] -> a0)) 

     arising from a use of `show' 
    Possible fix: add an instance declaration for (Show ([Char] -> a0)) 
    In the first argument of `(++)', namely `show length' 
    In the expression: show length ++ ' ' : show (length "Hello") 
    In the expression: 
     let length = 2 in show length ++ ' ' : show (length "Hello") 

Và đây là ví dụ của bạn:

*Main> let e = exp 1 in show e ++ " " ++ let e = 2 in show e 
"2.718281828459045 2" 

Tôi sẽ thêm dấu ngoặc để nhấn mạnh phạm vi:

*Main> let e = exp 1 in (show e ++ " " ++ (let e = 2 in (show e))) 
"2.718281828459045 2" 

Đầu tiên e bị ẩn thay vì chỉnh sửa. Tính minh bạch tham chiếu được giữ nguyên, nhưng nó chắc chắn là thực hành không tốt vì nó khó theo dõi.


Bây giờ bí mật dấu nhắc tương tác là một chút như một do khối lớn trong đơn nguyên IO, vì vậy chúng ta hãy nhìn vào đó:

testdo = do 
    let e = exp 1 
    print e 
    let e = 2 
    print e 

Bây giờ tôi phải thừa nhận rằng trông một awful nhiều như vi phạm minh bạch tham chiếu, nhưng lưu ý rằng điều này có vẻ như nó cũng vậy:

testWrite = do 
    writeFile "test.txt" "Hello Mum" 
    xs <- readFile "test.txt" 
    print xs 
    writeFile "test.txt" "Yo all" 
    xs <- readFile "test.txt" 
    print xs 

Bây giờ chúng ta có tính minh bạch tham chiếu theo nghĩa nào? xs đề cập rõ ràng đến hai chuỗi khác nhau. Vâng, ký hiệu do này thực sự có ý nghĩa gì? Đó là cú pháp đường cho

testWrite = writeFile "test.txt" "Hello Mum" 
     >> readFile "test.txt" 
     >>= (\xs -> print xs 
     >> writeFile "test.txt" "Yo all" 
     >> readFile "test.txt" 
     >>= (\xs -> print xs)) 

Bây giờ, rõ ràng hơn rằng nhiệm vụ giống như nhiệm vụ chỉ là phạm vi địa phương một lần nữa. Có thể bạn đang hạnh phúc khi làm

increment :: [Int] -> [Int] 
increment = \x -> map (\x -> x+1) x 

Điều này cũng làm tương tự.


Tóm tắt
gì dường như là nhiệm vụ chỉ là giới thiệu của một phạm vi địa phương mới. Phew. Nếu bạn sử dụng rất nhiều, bạn làm cho nó rất không rõ ràng những gì mã của bạn có nghĩa là.

+6

Lưu ý rằng câu hỏi sử dụng 'let' trong ngữ cảnh không ghi chú tức là' do {...; để e = 1; ...} 'chứ không phải trong ngữ cảnh' cho ... trong ... '. Lý do khá giống hệt nhau, nhưng nó đáng nói đến. – huon

+0

@dbaupp Điểm tốt. Đề cập. Cảm ơn. – AndrewC

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