Haskellで引数の型を可変に
C++やら.Netやらでよくあるような同じ名称だけど異なる引数を持つ関数(正しい名称は忘れたけど)ってHaskellでできないんだろうかと思って調べた。
結論としては関数も型なのでできるのだが、FlexibleInstances拡張を入れる必要があるっぽい。
以下がすごい適当な例。
{-# LANGUAGE FlexibleInstances #-} class TestFunc a where testFunc :: a instance TestFunc Integer where testFunc = -1 instance TestFunc String where testFunc = "test!!" instance TestFunc (() -> Integer) where testFunc a = -2 instance TestFunc (Integer -> Integer) where testFunc a = a + 1 instance TestFunc (Integer -> Integer -> Integer) where testFunc a b = a + b + 1 instance TestFunc ((Integer, Integer) -> Integer) where testFunc (a, b) = a + b - 1
ただ、これをやると、どのケースに該当するのか、型がなかなかうまく推論されてくれないので、ちょっと利便性は落ちる感じだなあ。
もっと便利に使う方法とかないのだろうか。
カリー化とか考えなくて、ある程度まで形が決まってるなら、以下みたいにやる方が型推論はうまく働いてくれるっぽい?
{-# LANGUAGE FlexibleInstances #-} class TestF a where testF :: Integral b => a -> b instance TestF Integer where testF a = fromIntegral $ a + 1 instance TestF Int where testF a = fromIntegral $ (toInteger a) + 1 -- 以下だとUndecidableInstances拡張が必要。 -- なんとなく理解はできるけどちょっと気持ち悪いなあ。 -- instance (Integral a) => TestF (a) where -- testF a = fromIntegral $ (toInteger a) + 1 instance (Integral a, Integral b) => TestF (a, b) where testF (a, b) = fromIntegral $ (toInteger a) + (toInteger b) + 1 instance (Integral a, Integral b, Integral c) => TestF (a, b, c) where testF (a, b, c) = fromIntegral $ (toInteger a) + (toInteger b) + (toInteger c) + 1 instance TestF String where testF s = fromIntegral $ 0
いろいろ試してみると型推論が効いたり効かなかったりする。理解できるものもあるけど、理解しがたい結果もある。
うーむ。まだ理解が甘いってことだろうか。