2011-12-17 6 views
20

私はYesNoの例をLearn You a Haskell for Great Good!から調べようとしています。ここで制約内のあいまいな型変数 `a0 '

は私のソースコードです:私は例外以下、このコードを実行

module Main where 

main :: IO() 

main = putStrLn (show (yesno 12)) 

class YesNo a where 
    yesno :: a -> Bool 


instance YesNo Bool where 
    yesno b = b 

instance YesNo [a] where 
    yesno [] = False 
    yesno _ = True 


instance YesNo Int where 
    yesno 0 = False 
    yesno _ = True 

が発生します。

Ambiguous type variable `a0' in the constraints: 
    (YesNo a0) arising from a use of `yesno' 
      at /Users/mkhadikov/Projects/personal/haskell/hello-world/yesno.hs:5:25-29 
    (Num a0) arising from the literal `12' 
      at /Users/mkhadikov/Projects/personal/haskell/hello-world/yesno.hs:5:31-32 
Probable fix: add a type signature that fixes these type variable(s) 
In the first argument of `show', namely `(yesno 12)' 
In the first argument of `putStrLn', namely `(show (yesno 12))' 
In the expression: putStrLn (show (yesno 12)) 

あなたはこのコードが悪いのか説明していただけますか?

答えて

31

問題は、タイプ12がわからないということです。 putStrLn (show (yesno (12 :: Int)))を試してください:あなたが直接するタイプを指定する必要が

:それはヌムインスタンスとあらゆるタイプにすることができます。

なぜGHCは他の選択肢もないので、Intを選択できないのですか?良い質問。答えは、Haskellのtypeclassシステムでは、インスタンスを追加することで既存の正しいプログラムを無効にしたり、動作を変更したりすることができないということです。 (これは、というオープンワールドの仮定と呼ばれます)。もしそれがIntを選択した場合、instance YesNo Integerを追加するとどうなりますか?選択肢があいまいになり、プログラムが壊れてしまいます。

多型の値を持つこのようなtypeclassを使用する場合は、より正確な型を指定する必要があります。これは実際にはあまり出てこないはずです。なぜなら、通常は型があなたの望むものになるように周囲の文脈があるからです。これは、主に数値リテラルで、これによって影響を受けます。

5

12は実際にはNum a => aで、Intではありません。 12 :: Intのような明示的な型アノテーションを追加すると、コンパイルする必要があります。

+0

それはHaskellでは '12'のように動作データ構築の独自の種類を作成することは可能ですか?データコンストラクタを作成するたびに、単一の型の値が構築されるようです。しかし、 '12'と書くと、見ることができるように、単一の型の値ではなく、Numで制約されている型の値を構築します。したがって、Num a => aとなります。私はこれを正しく解釈していますか?この種のものは、実在の/共用体を持つ値を作るのと同じですか? – CMCDragonkai

+0

@CMCDragonkai私は細部について少しばかげていますが、基本的にtypeclassのNumは関数fromInteger :: Num a => Integer - > a'を含んでいます。数値リテラルは 'fromInteger'が呼び出されたかのように動作します。 – fuz

+0

ああ、だから 'a'はある種の存在/共用体になります。とても興味深い。 – CMCDragonkai

1

私は同じ問題を抱えていました。

は、これはおそらく、最高の一つの解決策ではありませんが、それは動作します:

class YesNo a where 
    yesno :: a -> Bool 


instance YesNo Int where 
    yesno 0 = False 
    yesno _ = True 


instance YesNo Integer where 
    yesno 0 = False 
    yesno _ = True 
関連する問題