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à.
@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