この種の問題を解決するための 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
クラスの両方にある必要があることを明示します。Eq
Num
これらのクラスの制約はどこから来るのでしょうか? 最初の ( for Eq
) は、2 つの入力リストの要素を と比較することによって導入されます/=
。2 番目 ( for Num
) は、最初のリストの要素を数値 ( 0
) と比較します。
これで、指定した型シグネチャはString -> String -> Bool
. 文字列は単なる文字のリストであるため、これは に展開され[Char] -> [Char] -> Bool
ます。これを推測された署名と比較すると、署名は で型変数a
をインスタンス化しますChar
。Eq
-constraint on に関する限り、実際に のインスタンスであるため、a
これは問題ありません。ただし、必要に応じて、のインスタンスではありません(そのため、コンパイラはテストの実行方法を知ることができません); したがって、型エラーです。Char
Eq
Char
Num
x /= 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'
) は問題なくコンパイルされます。