関数のコンテキストの型はユニークに解決される
言われてみれば当たり前なのですが、これに嵌りました。
Num
型を複数とる関数があって、Int
型やDouble
型などいろいろパラメータに与えたかったのですが、コンパイルエラーがとれませんでした。問題点をシンプルな例で示すと以下のようになります。
Num
型を複数とる関数を定義します。数値のリストを2つとり、それぞれの要素を掛け合わせて、合計を取ります。
*Main> let sumtimes' = \xs ys -> sum $ zipWith (*) xs ys *Main> :t sumtimes' sumtimes' :: Num a => [a] -> [a] -> a
普通に動きます。
*Main> sumtimes' [1,2,3] [1,2,3] <interactive>:4:1: warning: [-Wtype-defaults] • Defaulting the following constraints to type ‘Integer’ (Num a0) arising from a use of ‘it’ at <interactive>:4:1-25 (Show a0) arising from a use of ‘print’ at <interactive>:4:1-25 • In the first argument of ‘print’, namely ‘it’ In a stmt of an interactive GHCi command: print it 14 *Main> sumtimes' [1.0,2.0,3.0] [1.0,2.0,3.0] <interactive>:5:1: warning: [-Wtype-defaults] • Defaulting the following constraints to type ‘Double’ (Fractional a0) arising from a use of ‘it’ at <interactive>:5:1-37 (Show a0) arising from a use of ‘print’ at <interactive>:5:1-37 • In the first argument of ‘print’, namely ‘it’ In a stmt of an interactive GHCi command: print it 14.0
型が曖昧で、ワーニングが出ていますが、型を明示的に指定すれば、ワーニングはなくなります。
*Main> sumtimes' [1::Int,2,3] [1,2,3] 14 *Main> sumtimes' [1,2,3] [1,2::Double,3] 14.0
ここまでは良いのですが、2つのバラメータに別の数値型のリストを与えた時は、コンパイルエラーになります。ここに気づかず時間を取られていまいました。
*Main> sumtimes' [1::Int,2,3] [1::Double,2,3] <interactive>:8:25: error: • Couldn't match expected type ‘Int’ with actual type ‘Double’ • In the expression: 1 :: Double In the second argument of ‘sumtimes'’, namely ‘[1 :: Double, 2, 3]’ In the expression: sumtimes' [1 :: Int, 2, 3] [1 :: Double, 2, 3] *Main>
Int
とInteger
でもコンパイルエラーになります。
*Main> sumtimes' [1::Int,2,3] [1::Integer,2,3] <interactive>:12:25: error: • Couldn't match expected type ‘Int’ with actual type ‘Integer’ • In the expression: 1 :: Integer In the second argument of ‘sumtimes'’, namely ‘[1 :: Integer, 2, 3]’ In the expression: sumtimes' [1 :: Int, 2, 3] [1 :: Integer, 2, 3] *Main>
Num a => [a] -> [a] -> a
の2つのパラメータは同じa
となっているので、同じ型でなければなりません。Nun
型のインスタンスならなんでもいいわけではありません。