2012-02-27 44 views
51

Tại sao typecheck này:runST và chức năng thành phần

runST $ return $ True 

Trong khi sau không:

runST . return $ True 

GHCI phàn nàn:

Couldn't match expected type `forall s. ST s c0' 
      with actual type `m0 a0' 
Expected type: a0 -> forall s. ST s c0 
    Actual type: a0 -> m0 a0 
In the second argument of `(.)', namely `return' 
In the expression: runST . return 
+7

Nếu '($)' có thể được cung cấp một chữ ký được đánh dấu là '($): forall (a: *) (b: a -> *). ((x: a) -> b x) -> (x: a) -> b x' nó sẽ hoạt động mà không có thủ thuật GHC, và tương tự cho '(.)'. – danr

Trả lời

47

Câu trả lời ngắn gọn là suy luận kiểu không phải lúc nào cũng hoạt động với các loại xếp hạng cao hơn. Trong trường hợp này, nó là không thể suy ra các loại (.), nhưng nó gõ kiểm tra nếu chúng ta thêm một loại chú thích rõ ràng:

> :m + Control.Monad.ST 
> :set -XRankNTypes 
> :t (((.) :: ((forall s0. ST s0 a) -> a) -> (a -> forall s1. ST s1 a) -> a -> a) runST return) $ True 
(((.) :: ((forall s0. ST s0 a) -> a) -> (a -> forall s1. ST s1 a) -> a -> a) runST return) $ True :: Bool 

Vấn đề tương tự cũng xảy ra với ví dụ đầu tiên của bạn, nếu chúng ta thay thế ($) với riêng của chúng tôi phiên bản:

> let app f x = f x 
> :t runST `app` (return `app` True) 
<interactive>:1:14: 
    Couldn't match expected type `forall s. ST s t0' 
       with actual type `m0 t10' 
    Expected type: t10 -> forall s. ST s t0 
     Actual type: t10 -> m0 t10 
    In the first argument of `app', namely `return' 
    In the second argument of `app', namely `(return `app` True)' 

một lần nữa, điều này có thể được giải quyết bằng cách thêm loại chú thích:

> :t (app :: ((forall s0. ST s0 a) -> a) -> (forall s1. ST s1 a) -> a) runST (return `app` True) 
(app :: ((forall s0. ST s0 a) -> a) -> (forall s1. ST s1 a) -> a) runST (return `app` True) :: Bool 

gì đang xảy ra ở đây là rằng có một quy tắc nhập đặc biệt trong GHC 7 chỉ áp dụng cho toán tử chuẩn ($). Simon Peyton-Jones giải thích hành vi này trong a reply on the GHC users mailing list:

Đây là một ví dụ động cơ thúc đẩy cho loại suy luận rằng có thể đối phó với loại impredicative. Xem xét các loại ($):

($) :: forall p q. (p -> q) -> p -> q 

Trong ví dụ chúng ta cần phải nhanh chóng p với (forall s. ST s a), và đó là những gì polymorphism impredicative có nghĩa là: instantiating một loại biến với một kiểu đa hình .

Đáng buồn thay, tôi biết không có hệ thống phức tạp hợp lý nào có thể đánh máy [điều này] chưa được thanh toán. Có rất nhiều hệ thống phức tạp và tôi có là đồng tác giả trên các giấy tờ trên ít nhất hai, nhưng tất cả đều là Quá Jolly Phức tạp để sống trong GHC. Chúng tôi đã triển khai loại boxy, nhưng tôi đã loại bỏ nó khi triển khai trình kiểm tra lỗi mới. Không ai hiểu nó.

Tuy nhiên, người ta thường xuyên viết

runST $ do ... 

rằng trong GHC 7 Tôi thực hiện một quy tắc gõ đặc biệt, chỉ dành riêng cho sử dụng ghi vào của ($). Chỉ cần nghĩ về (f $ x) dưới dạng một dạng cú pháp mới , với quy tắc nhập rõ ràng và bạn không thể đi.

Ví dụ thứ hai của bạn không thành công vì không có quy tắc như vậy cho (.).

+0

Cảm ơn, giờ nó bắt đầu có ý nghĩa. –

33

Các mô hình runST $ do { ... } là quá phổ biến, và thực tế là thông thường việc không kiểm tra là rất khó chịu, GHC bao gồm một số ST -kiểm tra kiểu kiểm tra đặc biệt để làm cho nó hoạt động. Những hacks này có thể bắn ở đây cho phiên bản ($), nhưng không phải là phiên bản (.).

+0

Điểm thú vị. Nó có lẽ là đủ để chỉ cần thả ($) ngay sau khi nó được nhìn thấy rằng nó được áp dụng cho 2 đối số. Nên dễ dàng xác minh bằng cách thay thế bằng chức năng tùy chỉnh giống như ($), và xem liệu trình kiểm tra loại có thể khiếu nại không. – Ingo

+1

@Ingo: Yep, '' 'cho phép ứng dụng f x = f x trong runST' app' (trả về 'ứng dụng' Đúng)' '' không thể đánh dấu kiểm tra. Hấp dẫn. – hammar

+1

@Hammar: Điều này có nghĩa, GHC dường như giảm $ mặc dù điều này không hoàn toàn chính xác với các loại xếp hạng cao hơn. – Ingo

3

Các thông báo có chút khó hiểu về điểm (hoặc vì vậy tôi cảm thấy). Hãy để tôi viết lại mã của bạn:

runST (return True) -- return True is ST s Bool 
(runST . return) True -- cannot work 

Một cách khác để đặt này là monomorphic m0 a0 (kết quả lợi nhuận, nếu nó sẽ nhận được một a0) không thể được thống nhất với (forall s.ST s a).

+0

Điều này thực hiện typecheck: 'unsafePerformIO. return $ True' –

+3

@Ingo: Bạn đang phân tích hai ví dụ sai. 'runST $ return $ True' là' ($) runST (($) trả về True) ', và' runST. return $ True' là '($) ((.) runST return) True'. Họ sẽ làm điều tương tự khi không có loại rank-2. – ehird

+1

@ehird - Bạn nói đúng, tôi đã quên dấu chấm. (Này, vần điệu đó ...) – Ingo

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