IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

関数のコンテキストの型はユニークに解決される

言われてみれば当たり前なのですが、これに嵌りました。

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>

IntIntegerでもコンパイルエラーになります。

*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型のインスタンスならなんでもいいわけではありません。