2012-10-25 70 views
6

爲什麼這個代碼正確爲什麼我不能用這個非參數化類型創建實例?

instance Functor IO where -- note that IO isn't parametrized, and it's correct 
    fmap f action = do 
     result <- action 
     return (f result) 

但下面的代碼有一個編譯器錯誤?

class Print a where 
    print :: a -> String 

data A t = A t 
instance Print A where -- error: expecting one more argument to `A' 
    print a = "abc" 

回答

10

這是因爲kinds不匹配。常規類型有*,而類型構造函數(如AIO)有* -> *類型,表示它們需要類型參數才能返回類型。

Print類的定義中,編譯器推斷出因爲a用作普通類型,所以它必須具有種類*。然而,Functor作品上的那種* -> *類型構造:

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

這裏,f不作爲一個普通的類型,但作爲一個類型構造,因此它推斷出一種是* -> *。您可以在GHCI的:kind命令來驗證這一點:

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

當你說

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

您確保a必須是一個類型的,但是當你說

data A t = A t 

你讓A類型構造 - A不例如,類型,但A Int是。 A是一種類型的函數,但Print類中的a必須是類型值,而不是類型函數。

你可以做

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

這對IO OK,因爲Functor類要求一個類型構造。

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

你可以看到,自f a是一種類型,f是一種構造,就像IOA是。 你就可以做

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

,你會不會是能夠做到

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

(我用print'代替print以避免與標準功能print衝突。)

1

嘗試精神(或用文本編輯器)在類定義與您在實例中使用的類型給出的類型填充。

來源:

class Print a where 
    print :: a -> String 

data A t = A t 

我們要

instance Print A 

所以,在類型的類定義我們說的Aa是instnace,我們得到這個:

class Print A where 
    print :: A -> String 

嗯。 A -> String作爲一個類型沒有意義,因爲函數類型的箭頭在左邊是一個類型,右邊是一個類型,並給出函數類型。但A不是一種類型,因爲您聲明Adata A t; A t是任何類型t的類型,但A型構造函數。如果將它應用於某種類型,它可以是一種類型,但A本身是不同的。因此,您可以將A t設爲Print的一個實例,但本身不能設爲A

那麼爲什麼instance Functor IO工作?讓我們看一下類的定義:

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

現在讓我們嘗試fIO

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

IO的終了了適用於類型參數,所以這是可行的。如果我們試圖製作一個具體類型如IntA tFunctor的實例,那麼我們會遇到問題。

相關問題