2012-10-25 41 views

Trả lời

10

Điều này là do kinds không khớp. Các kiểu thông thường có loại *, trong khi các hàm tạo kiểu như A hoặc IO có loại * -> *, cho biết rằng chúng cần một tham số kiểu để trả về một kiểu.

Trong định nghĩa lớp Print, trình biên dịch cho rằng vì a được sử dụng làm loại đồng bằng, phải có loại *. Tuy nhiên, Functor công trình vào loại nhà xây dựng thuộc loại * -> *:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Ở đây, f không được sử dụng như một loại đơn giản, nhưng như một constructor loại, vì vậy nó suy ra loại là * -> *. Bạn có thể xác minh điều này bằng lệnh :kind trong GHCi:

> :kind Print 
Print :: * -> Constraint 
> :kind Functor 
Functor :: (* -> *) -> Constraint 
9

Khi bạn nói

class Print a where 
    print' :: a -> String 

Bạn hãy chắc chắn rằng a có phải là một loại, nhưng khi bạn nói

data A t = A t 

bạn thực hiện A một constructor loại - A không phải là một loại, nhưng ví dụ: A Int. A là một loại chức năng trên các loại, nhưng a trong lớp In phải là một giá trị kiểu, không phải là một hàm kiểu.

Bạn có thể làm

instance Print (A Int) where 
    print' a = "abc" 

Đó là OK cho IO vì lớp Functor yêu cầu một constructor loại.

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Bạn có thể thấy rằng kể từ khi f a là một loại, f là một constructor loại, giống như IOA đang có. Bạn sẽ có thể để làm

instance Functor A where -- OK, A is a constructor, Functor needs one 
    fmap f (A x) = A (f x) 

và bạn sẽ không thể làm

instance Eq IO where -- not OK - IO is a constructor and Eq needs a type 
    (==) = error "this code won't compile" 

(Tôi đã sử dụng print' thay vì print để tránh đụng độ với chức năng tiêu chuẩn print.)

1

Hãy thử tinh thần (hoặc với một trình soạn thảo văn bản) điền vào các loại được đưa ra trong định nghĩa lớp với loại mà bạn đã sử dụng trong ví dụ.

Từ:

class Print a where 
    print :: a -> String 

data A t = A t 

chúng tôi muốn

instance Print A 

Vì vậy, thay a trong định nghĩa kiểu lớp cho A chúng tôi đang nói là một instnace, chúng tôi nhận được điều này:

class Print A where 
    print :: A -> String 

Uh-oh. A -> String không có ý nghĩa như một loại, vì mũi tên kiểu hàm có một loại ở bên trái và một loại ở bên phải, và cung cấp cho bạn loại hàm. Nhưng A không phải là một loại, vì bạn đã khai báo A với data A t; A t là loại cho bất kỳ loại nào t, nhưng A là một phương thức khởi tạo loại . Nó có thể tạo ra một loại nếu bạn áp dụng nó cho một loại, nhưng chính bản thân nó là một cái gì đó khác. Vì vậy, bạn có thể tạo A t thành một phiên bản Print, nhưng không phải là A.

Vậy tại sao instance Functor IO hoạt động? Cho phép xem xét các định nghĩa lớp:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Bây giờ cho phép thử thay IO cho f:

class Functor IO where 
    fmap :: (a -> b) -> IO a -> IO b 

Các IO s cuối lên áp dụng cho gõ thông số, vì vậy nó tất cả các công trình ra. Ở đây, chúng tôi sẽ gặp sự cố nếu chúng tôi cố gắng tạo loại bê tông như Int hoặc A t một phiên bản của Functor.

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