0
versioncheck::String -> String -> Bool
versioncheck [] [] = True

versioncheck (x:xs) [] 
    |x /= 0 = False
    |otherwise = versioncheck xs [] 

versioncheck (x:xs) (y:ys) 
  | x /= y = False
  | otherwise = versioncheck xs ys 

「バージョンチェックの定義には Num Char のインスタンスが必要です」というエラーが表示されるのはなぜですか?

4

1 に答える 1

7

この種の問題を解決するための 1 つのアプローチ (そして私が推奨できるアプローチ) は、関数定義を型シグネチャなしでコンパイラーにフィードし、対話型環境を使用して、コンパイラーが関数に対して推論した型を検査することです。

あなたの場合、定義すると

versioncheck []     []     = True
versioncheck (x:xs) [] 
  |x /= 0                  = False
  |otherwise               = versioncheck xs [] 
versioncheck (x:xs) (y:ys) 
  | x /= y                 = False
  | otherwise              = versioncheck xs ys 

そして、GHCiで、クエリ

> :type versioncheck

それは私たちに与えます

versioncheck :: (Eq a, Num a) => [a] -> [a] -> Bool

関数が同じ型から引き出された要素を持つ 2 つのリストで動作すること、aおよびこの型が等しいかどうかをテストできる値を持つ型のクラスと数値型のaクラスの両方にある必要があることを明示します。EqNum

これらのクラスの制約はどこから来るのでしょうか? 最初の ( for Eq) は、2 つの入力リストの要素を と比較することによって導入されます/=。2 番目 ( for Num) は、最初のリストの要素を数値 ( 0) と比較します。

これで、指定した型シグネチャはString -> String -> Bool. 文字列は単なる文字のリストであるため、これは に展開され[Char] -> [Char] -> Boolます。これを推測された署名と比較すると、署名は で型変数aをインスタンス化しますCharEq-constraint on に関する限り、実際に のインスタンスであるため、aこれは問題ありません。ただし、必要に応じて、のインスタンスではありません(そのため、コンパイラはテストの実行方法を知ることができません); したがって、型エラーです。CharEqCharNumx /= 0

解決策の 1 つは、推測された署名を使用することですが、それが実際に処理したい文字のリストである場合は、テストを削除して文字値x /= 0と比較する必要があります。x例えば:

versioncheck :: String -> String -> Bool
versioncheck []     []     = True
versioncheck (x:xs) []
  |x /= '0'                = False
  |otherwise               = versioncheck xs []
versioncheck (x:xs) (y:ys)
  | x /= y                 = False
  | otherwise              = versioncheck xs ys

( の引用符に注意してください'0') は問題なくコンパイルされます。

于 2013-07-10T07:02:33.647 に答える