2008-12-02 43 views
6

Tôi đang cố gắng tìm hiểu xem Haskell có sử dụng phạm vi động hay tĩnh không. Tôi nhận ra rằng, ví dụ, nếu bạn xác định:Haskell sử dụng loại phạm vi nào?

let x = 10 

sau đó xác định chức năng

let square x = x*x 

Bạn có 2 khác nhau "x", và điều đó có nghĩa nó là tự động scoped? Nếu không, nó sử dụng phạm vi nào và tại sao?

Ngoài ra, biến Haskell có thể có bí danh (tên khác cho cùng một vị trí/giá trị bộ nhớ) không?

Cảm ơn.

+2

BTW, Sev, bạn có thể muốn xem xét xem bạn vẫn muốn giữ câu trả lời của igorgue là câu trả lời cho câu hỏi này, với điều kiện đã được chứng minh là sai trên điểm bí danh (xem trả lời dưới đây) và, trong khi có tranh luận về nó, anh ta không thể đưa ra bất kỳ lý lẽ nào mà anh ta không sai về điểm biến. –

Trả lời

5

Có một số điều sai trong báo cáo của bạn ...

  • không có biến có thể thay đổi trong Haskell chỉ định nghĩa (hoặc các biến không thay đổi)
  • một vị trí nhớ biến là một khái niệm không tồn tại trong Haskell

Trong ví dụ của bạn, xkhông 10 trong hàm chỉ là một cuộc tranh luận vuông, có thể lấy bất kỳ giá trị (bạn có thể chỉ định các loại sau) trong trường hợp này 10 nhưng chỉ trong trường hợp này.

Dưới đây là một ví dụ về bí danh được cung cấp bởi Curt Sampson:

import Data.IORef 

main :: IO() 
main = do x <- newIORef 0   -- write 0 into x 
      readIORef x >>= print -- x contains 0 
      let y = x 
      readIORef y >>= print -- y contains 0 
      writeIORef x 42   -- write 42 into x 
      readIORef y >>= print -- y contains 42 
+5

Chắc chắn Haskell có các biến. Xem http://stackoverflow.com/questions/993124/does-haskell-have-variables/993126 –

+2

không, nó không có biến !, "định nghĩa" là thuật ngữ đúng, hoặc nếu bạn muốn gọi chúng là biến, thì là những biến bất biến giống như trong Erlang. Tuy nhiên điều này rất khác với khái niệm bắt buộc của "biến". – igorgue

+3

igorgue, nếu bạn tin rằng Haskell không có biến, vui lòng đăng câu trả lời cho câu hỏi được liên kết ở trên cho chúng tôi biết lý do tại sao không. Không bao gồm "định nghĩa" của 'x' trong' f x = x * 2'. –

11

Sử dụng Haskell (nói rộng) chính xác cùng phạm vi từ vựng giống như hầu hết các ngôn ngữ khác.

ví dụ:

x = 10 

Kết quả trong một giá trị tham chiếu thông qua x trong phạm vi toàn cầu, trong khi

square x = x * x 

sẽ dẫn đến x được lexically scoped đến hàm vuông. Nó có thể giúp đỡ nếu bạn nghĩ về mẫu ở trên là một tính tinh vi cú pháp cho:

square = \ x -> x * x 

Như cho câu hỏi khác của bạn tôi không chắc chắn những gì bạn có ý nghĩa bởi aliasing

6

trả lời chỉ là phần thứ hai của câu hỏi:

Bạn có thể có một vài bí danh cho cùng một "bộ nhớ vị trí", nhưng vì họ tất cả đều không thay đổi, nó không quan trọng phần lớn thời gian.

Dumb dụ:

foo x y = x * y 
bar z = foo z z 

Khi trong foo gọi từ bar, cả xy rõ ràng giá trị như nhau. Nhưng vì bạn không thể sửa đổi hoặc là x hoặc y, bạn thậm chí sẽ không nhận thấy.

3

Như phần đầu tiên của câu hỏi đã được trả lời bởi những người khác, đây là phần thứ hai:

tôi giả bởi aliasing bạn có nghĩa là one name for another. Như Haskell là một ngôn ngữ chức năng, và các chức năng xử định danh như bình thường trong mọi trường hợp, bạn có thể làm điều đó như thế này:

y = x 

đó sẽ xác định một bí danh y cho hàm x. Lưu ý rằng mọi thứ đều là một hàm. Ngay cả khi nó trông giống như một "" biến ", nó chỉ là một hàm vô giá trị không có đối số. Bí danh với nhiều loại giống như thế này:

type Function = Double -> Double 

đó sẽ xác định một bí danh Function cho các loại Double -> Double

+1

"một hàm vô giá trị không có đối số" - Tôi chỉ chỉ ra rằng những nhận xét này không giữ đúng trong trường hợp giá trị chưa được lọc. – porges

2

Trong ví dụ của bạn, định nghĩa toàn cầu của x bị che bởi những nét địa phương của x. Trong Haskell, phạm vi của biến được xác định bằng cách đọc tĩnh mã nguồn - điều này được gọi là phạm vi từ vựng, nhưng có thể nhận được một cái gì đó tương tự với phạm vi động với các tham số ngầm định (nhưng điều đó có thể dẫn đến một số hành vi không mong muốn (tôi đã đọc; cố gắng 'em bản thân mình)).

1

Tổng hợp các câu trả lời khác ngắn gọn:

  1. phạm vi từ vựng
  2. răng cưa là dễ dàng như x = 1; y = x nhưng thường không thành vấn đề bởi vì điều này là không thay đổi.

Cú pháp let bạn sử dụng trong ví dụ của bạn có vẻ như nó ở dấu nhắc tương tác ghci>. Tất cả mọi thứ trong chế độ tương tác xảy ra trong đơn nguyên IO vì vậy mọi thứ có thể xuất hiện dễ biến đổi hơn so với bình thường.

0

Vâng, như tôi nghĩ mọi người đã nói rồi, Haskell không có bất kỳ biến nào như được tìm thấy trong hầu hết các ngôn ngữ khác, nó chỉ có biểu thức. Trong ví dụ của bạn let x = 10 x là một biểu thức luôn luôn ước lượng đến 10. Bạn không thể thay đổi giá trị của x sau này, mặc dù bạn có thể sử dụng các quy tắc phạm vi để ẩn nó bằng cách xác định x là một biểu thức khác.

+0

Tôi đã thử chúng và hành vi này thực sự khá rõ ràng, bởi vì bạn cần khai báo các biến có phạm vi động một cách rõ ràng trong định nghĩa kiểu nếu bạn sử dụng chúng. –

2

Haskell sử dụng phạm vi lồng nhau tĩnh. Điều gì hơi khó hiểu so với các ngôn ngữ khác có phạm vi lồng nhau tĩnh là phạm vi của tên là một khối bao gồm các bài kiểm tra trước định nghĩa của nó. Ví dụ:

evens = 0 : map (+1) odds 
odds = map : (+1) evens 

ở đây tên 'tỷ lệ' nằm trong định nghĩa 'evens', mặc dù thực tế đáng ngạc nhiên là 'tỷ lệ cược' chưa được xác định. (Ví dụ xác định hai danh sách vô hạn các số chẵn và lẻ.)

Ngôn ngữ chết có quy tắc phạm vi tương tự là Modula-3. Nhưng Haskell là một chút phức tạp hơn trong đó bạn có thể cố gắng 'xác định lại' một biến trong phạm vi tương tự nhưng thay vào đó bạn chỉ giới thiệu một phương trình đệ quy khác. Đây là một cái bẫy cho những người học ML hoặc Đề án thứ nhất:

let x = 2 * n 
    x = x + 1 -- watch out! 

này là hoàn toàn tốt ML hay Scheme phép *, nhưng Haskel có kế hoạch letrec ngữ nghĩa, mà không có sự hạn chế các giá trị lambda. Không có thắc mắc đây là thứ khó!

+0

Err ... Tôi nghĩ rằng bạn có nghĩa là phạm vi "bao gồm các định nghĩa khác theo định nghĩa", hoặc một cái gì đó như thế, phải không? –

+0

@Curt: Tôi giải thích rằng ông có nghĩa là phạm vi của định nghĩa "tỷ lệ cược" bao gồm phần trước của khối, nơi bạn diễn giải theo cách khác, với * sử dụng * của "tỷ lệ cược" được tra cứu bao gồm các định nghĩa sau. –

+0

Có thể truy cập các biến cục bộ bên ngoài phạm vi mà chúng được khai báo không? –

0

Có, Haskell có bí danh. Hãy thử chương trình nhỏ này:

import Data.IORef 

main :: IO() 
main = do x <- newIORef 0   -- write 0 into x 
      readIORef x >>= print -- x contains 0 
      let y = x 
      readIORef y >>= print -- y contains 0 
      writeIORef x 42   -- write 42 into x 
      readIORef y >>= print -- y contains 42 
Các vấn đề liên quan