2012-10-25 10 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" 

を行うことができ

Functorクラスは型コンストラクタを要求するので、それはIOためOKです。

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 

をしたい、私たちが言っているAのための型クラス定義でaを代入することはinstnaceあり、我々はこれを得る:

class Print A where 
    print :: A -> String 

あああ。 A -> Stringは型としては意味がありません。なぜなら、関数型の矢印は左の型と右の型を取り、関数型を提供するからです。しかし、Adata A tAと宣言しているため、タイプではありません。 A tは任意のタイプtのタイプですが、Aタイプのコンストラクタです。型に適用すると型を作ることができますが、A自体は別のものです。したがってA tPrintのインスタンスにすることはできますが、Aはインスタンスにすることはできません。

なぜinstance Functor IOは機能しましたか?クラス定義を見てみましょう:

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

は今fためIOに置き換えて試すことができます:

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

IO sのエンドアップはパラメータを入力するために適用されるので、すべてがうまくいきます。 IntまたはA tのインスタンスがFunctorのような具体的なタイプを作成しようとすると、ここで問題が発生します。

関連する問題