2015-04-15 13 views
7

Tôi vừa biết về tính năng StablePointer của GHC, điều này thực sự tuyệt vời, nhưng tôi không thể hiểu tại sao nó không hiển thị mọi thứ như nhau. Đây là trường hợp thử nghiệm của tôi:GHC StablePointer equality reasoning

-- Example 1 
import System.Mem.StableName 

data Wrapper = Wrapper { getWrapper :: Int -> Bool } 

myFunc :: Int -> Bool 
myFunc = (> 4) 

main :: IO() 
main = do 
    let m = Wrapper myFunc 
    a <- makeStableName $ getWrapper m 
    b <- makeStableName $ getWrapper m 
    print (a `eqStableName` b) 
    putStrLn "Done" 

Khá đơn giản, nhưng khi tôi làm runhaskell với GHC 7.8.4, tôi nhận được một kết quả của sai lầm. Điều gì về một trường hợp đơn giản? Hãy thử điều này:

-- Example 2 
import System.Mem.StableName 

main :: IO() 
main = do 
    let m = (+2) :: Int -> Int 
     n = m 
    a <- makeStableName m 
    b <- makeStableName n 
    print (a `eqStableName` b) 
    putStrLn "Done" 

Tôi vẫn nhận được kết quả là False. Cách duy nhất tôi có thể nhận được eqStableName để trả lại True là khi tôi gọi makeStableName trên cùng một biến ràng buộc chính xác. Như thế này:

-- in this example, r can be anything 
    a <- makeStableName r 
    b <- makeStableName r 
    print (a `eqStableName` b) 

Nhưng điều này không còn hữu ích nữa. Tôi đã biết rằng mọi biểu thức là bằng chính nó, vì vậy điều này không cho tôi bất kỳ thông tin mới nào. Câu hỏi của tôi là gấp đôi:

  1. Trường hợp sử dụng nào là StablePointer có ý định đáp ứng?
  2. Làm cách nào chúng tôi có thể giải thích về sự bình đẳng của StablePointer. Tôi biết rằng nó mang lại những âm bản sai, nhưng trong hoàn cảnh nào tôi có thể mong đợi những điều này luôn luôn xảy ra?

Cảm ơn mọi thông tin chi tiết. Họ được nhiều đánh giá cao.

- EDIT -

tôi phát hiện ra rằng nếu tôi xây dựng nó với ghc thay vì runhaskell, sau đó Ví dụ 2 thực sự không cho thấy họ đều bình đẳng. Ví dụ 1 vẫn không thành công. Câu hỏi vẫn đứng vững.

+2

Bạn đã cố gắng sử dụng '==' thay vì 'eqStableName'? – Bakuriu

+0

Tôi vừa thử và không tạo ra sự khác biệt nào. Tôi đã không nhận thấy rằng 'StablePointer a' có một cá thể' Eq', nhưng bây giờ bạn đã chỉ ra rằng, tôi thấy rằng việc sử dụng '==' có vẻ thích hợp hơn cho trường hợp của tôi, vì tôi đang kiểm tra bình đẳng trên mọi thứ cùng loại. –

Trả lời

8

Lý do những người trả lại False có lẽ là sự lười biếng. Trong GHC, mn sẽ đề cập đến các khối khác nhau, vì chúng chưa được đánh giá. makeStableName không bắt buộc giá trị. Nếu bạn tự buộc thunk, họ sẽ giống nhau:

let m = Wrapper myFunc 
    a <- makeStableName $! getWrapper m 
    b <- makeStableName $! getWrapper m 
    print (a `eqStableName` b) 

này in True (The $! sẽ buộc các giá trị được trả về bởi getWrapper để WHNF).

Lưu ý rằng nếu bạn không sử dụng runhaskell nhưng thay vì biên dịch với -O1, GHC sẽ thực sự biên dịch mã này sao cho nó in True. Từ cách nhìn vào cốt lõi, có vẻ như những gì GHC đã làm được nội tuyến mgetWrapper để các mã được chạy là một cách hiệu quả này:

a <- makeStableName myFunc 
b <- makeStableName myFunc 

nào thì tất nhiên tạo ra con trỏ ổn định tương tự.

Vì vậy, nếu bạn muốn có sự bình đẳng tối đa, luôn buộc các giá trị của bạn trước khi tạo con trỏ ổn định cho chúng. Không có guarrante mặc dù nếu hai giá trị bằng nhau mà chúng được gán con trỏ ổn định bằng nhau.

Nếu bạn chưa đọc nó, tôi cũng khuyên bạn nên đọc Stretching the storage manager giải thích việc triển khai các con trỏ ổn định.

+0

Cảm ơn bạn. Điều này trả lời câu hỏi của tôi, và tôi chắc chắn sẽ đọc bài báo tối nay. –

+1

Đối với những người quan tâm đến tương lai, trang 7 giải thích các ý tưởng trong câu trả lời này khá tốt. –