haskell アドホック多相
アドホック多相の意味がわかったかも
今までパラメータ多相でf x=x+1を型宣言しても以下の様にエラーが出ていた
Prelude> let f::a->a ; f x=x+1 <interactive>:1:21: Could not deduce (Num a) from the context () arising from the literal `1' at <interactive>:1:21 Possible fix: add (Num a) to the context of the type signature for `f' In the second argument of `(+)', namely `1' In the expression: x + 1 In the definition of `f': f x = x + 1
実はこれは(+)が Int,Integer,Float,Doubleをインスタンスとして持つNumクラスでaの制約として働いている。
Prelude> :t (+) (+) :: Num a => a -> a -> a
だから (+) は Charじゃ使えないんだよな。
ここで fを引数をそのままとして返す関数をつくって制約について実験していく
Prelude> let f::a->a; f x=x in f 1 1 it :: Integer Prelude> let f::a->a; f x=x in f "a" "a" it :: [Char] Prelude> let f::a->a; f x=x in f 'a' 'a' it :: Char
パラメータ多相ではどんな型の引数も受け付けている。
Prelude> let f::Num a=>a->a; f x=x in f 1 1 it :: Integer Prelude> let f::Num a=>a->a; f x=x in f 1.0 1.0 it :: Double Prelude> let f::Num a=>a->a; f x=x in f 'a' <interactive>:1:30: No instance for (Num Char) arising from a use of `f' at <interactive>:1:30-34 (略)
Numクラスで制約を行うとCharでははじくようになる
同様に Integralクラスで制約を行うと Doubleをはじくようになる
Prelude> let f::Integral a=>a->a; f x=x in f 1 1 it :: Integer Prelude> let f::Integral a=>a->a; f x=x in f (1::Int) 1 it :: Int Prelude> let f::Integral a=>a->a; f x=x in f (1::Integer) 1 it :: Integer Prelude> let f::Integral a=>a->a; f x=x in f 1.0 <interactive>:1:35: Ambiguous type variable `t' in the constraints: `Integral t' arising from a use of `f' at <interactive>:1:35-39 `Fractional t'
だから IntegralクラスのメソッドであるmodとFractionalクラスのメソッドである(/)は通常では共存できない
Prelude> let f x y= (mod x y==0)&&(x/y<10) in f 6 3 <interactive>:1:38: Ambiguous type variable `t' in the constraints: `Fractional t' arising from a use of `f' at <interactive>:1:38-42 `Integral t' arising from a use of `f' at <interactive>:1:38-42 Probable fix: add a type signature that fixes these type variable(s)
ここでfromIntegralの以下の性質を利用して Num型に引き上げる
Prelude> :t fromIntegral (3::Integer) fromIntegral (3::Integer) :: Num b => b
こうすることで/が使えるようになる。
Prelude> let f::Integral a=>a->a->Bool; f x y= mod x y==0 && (fromIntegral x)/(fromIntegral y)< 10 in f 6 3 True it :: Bool
たぶんこの理解であってると思う。
だから一番最初のやつは
Prelude> let f::Num a=>a->a ; f x=x+1 in f 2 3 it :: Integer
でいいとおもう。