Đơn nguyên ST hoạt động như thế nào?


77

Tôi hiểu rằng đơn nguyên ST giống như một đứa em trai nhỏ của IO, đến lượt nó là đơn nguyên nhà nước có thêm RealWorldphép thuật. Tôi có thể hình dung tiểu bang và tôi có thể hình dung rằng RealWorld được bằng cách nào đó đưa vào IO, nhưng mỗi lần tôi viết một loại chữ ký của STcác scủa ST đơn nguyên confuses me.

Lấy ví dụ ST s (STArray s a b),. Làm thế nào để slàm việc ở đó? Có phải nó chỉ được sử dụng để xây dựng một số phụ thuộc dữ liệu nhân tạo giữa các phép tính mà không thể tham chiếu như các trạng thái trong đơn nguyên trạng thái (do forall)?

Tôi chỉ đang đưa ra các ý tưởng và thực sự sẽ đánh giá cao một ai đó hiểu biết hơn tôi để giải thích cho tôi.


Nếu bạn tìm kiếm "ST đơn nguyên", có một mục nhập trả lời câu hỏi của tôi như một câu trả lời phụ cho câu hỏi về STArrays. Không chắc liệu câu hỏi của tôi có trùng lặp hay không. stackoverflow.com/questions/8197032/…
David

2
Thật hấp dẫn khi chỉ trả lời "Có". cho câu hỏi của bạn. :)
AndrewC

Tôi đoán việc thêm một liên kết vào câu hỏi và đóng nó sẽ a) giúp tìm kiếm câu hỏi này dễ dàng hơn trong tương lai và b) tiết kiệm thời gian cho một số người trả lời.
David

2
Tôi sẽ chỉ cho bạn bài viết của tôi về các loại xếp hạng 2 , điều này cũng sẽ giúp bạn hiểu STđơn nguyên. Khi bạn hiểu cách các kiểu xếp hạng-2 có thể kiểm soát "ai chọn" kiểu được sử dụng cho một biến kiểu, điều đó sẽ giúp bạn hiểu cách các STphép toán sử dụng xếp hạng 2 để ngăn các phép tính của nó bị sử dụng bất hợp pháp.
Luis Casillas

Bạn có thể viết a :: ST Int Int; a = return 2 STlà một đơn nguyên trạng thái hoàn toàn bình thường, ngoại trừ nó sử dụng một cặp không được đóng hộp làm đầu ra của hàm trạng thái State# s -> (# State# s, a #)khiến nó không thực tế để xử lý. Bí ẩn là hoàn toàn trong runSTđó có một loại hạng 2, mặc dù bản thân ST không phải là một.
áp dụng

Câu trả lời:


75

Các sgiữ đối tượng bên trong STđơn nguyên từ rò rỉ ra bên ngoài của các STđơn nguyên.

-- This is an error... but let's pretend for a moment...
let a = runST $ newSTRef (15 :: Int)
    b = runST $ writeSTRef a 20
    c = runST $ readSTRef a
in b `seq` c

Được rồi, đây là lỗi kiểu (đó là một điều tốt! Chúng tôi không muốn STRefrò rỉ ra bên ngoài tính toán ban đầu!). Đó là một lỗi loại vì phần phụ s. Hãy nhớ rằng runSTcó chữ ký:

runST :: (forall s . ST s a) -> a

Điều này có nghĩa là stính toán mà bạn đang chạy không có ràng buộc nào đối với nó. Vì vậy, khi bạn cố gắng đánh giá a:

a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))

Kết quả sẽ có loại STRef s Int, đó là sai vì sđã "thoát" bên ngoài foralltrong runST. Các biến kiểu luôn phải xuất hiện bên trong a forallvà Haskell cho phép các bộ forallđịnh lượng ngầm ở mọi nơi. Đơn giản là không có quy tắc nào cho phép bạn tìm ra kiểu trả về một cách có ý nghĩa a.

Một ví dụ khác với forall: Để hiển thị rõ ràng lý do tại sao bạn không thể cho phép mọi thứ thoát khỏi a forall, đây là một ví dụ đơn giản hơn:

f :: (forall a. [a] -> b) -> Bool -> b
f g flag =
  if flag
  then g "abcd"
  else g [1,2]

> :t f length
f length :: Bool -> Int

> :t f id
-- error --

Tất nhiên f idlà một lỗi, vì nó sẽ trả về một danh sách Charhoặc một danh sách Inttùy thuộc vào việc boolean là true hay false. Nó chỉ đơn giản là sai, giống như ví dụ với ST.

Mặt khác, nếu bạn không có stham số kiểu thì mọi thứ sẽ kiểm tra kiểu tốt, mặc dù mã rõ ràng là không có thật.

Cách ST thực sự hoạt động: Về mặt triển khai, STđơn nguyên thực sự giống với IOđơn nguyên nhưng có giao diện hơi khác. Khi bạn sử dụng STđơn nguyên bạn thực sự nhận được unsafePerformIOhoặc tương đương, ở hậu trường. Lý do bạn có thể thực hiện việc này một cách an toàn là vì chữ ký kiểu của tất cả STcác hàm liên quan, đặc biệt là phần có forall.


Bạn có thể "phá vỡ" sự an toàn của ST bằng cách sử dụng realWorld#trực tiếp trong mã máy khách, để bắt chước runSTRep? Tất nhiên đó là một ý tưởng tồi, nhưng tôi đang tự hỏi các biện pháp bảo vệ là gì, bên cạnh đó realworld#là một giá trị rõ ràng không an toàn để sử dụng trong một chương trình. hackage.haskell.org/package/base-4.6.0.1/docs/src/…
misterbee

@misterbee Yep , và nó thậm chí không nhất thiết là không an toàn. Hãy nhớ rằng, schỉ tồn tại ở cấp độ loại.
PyRulez

28

Đây schỉ là một vụ hack khiến hệ thống loại ngừng bạn làm những việc không an toàn. Nó không "làm" bất cứ điều gì trong thời gian chạy; nó chỉ làm cho trình kiểm tra loại từ chối các chương trình làm những điều đáng ngờ. (Nó được gọi là một loại ma , một thứ chỉ tồn tại trong đầu của người kiểm tra loại và không ảnh hưởng đến bất cứ điều gì trong thời gian chạy.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.