私は、Vector ライブラリを作成することによって、Haskell の型システムのより細かい部分を理解しようとしています。理想的には、C++ のように機能するオーバーロードされたベクトル乗算操作が必要です。つまり、任意のサイズのベクトルをスカラーで任意の順序で乗算できます。これを行うために、複数のパラメーター型クラスと型ファミリ拡張を組み合わせようとしました。
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}
data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)
class Vector a where
(<+>) :: a -> a -> a
class VectorMul a b where
type Result a b
(<*>) :: a -> b -> Result a b
instance (Num a) => Vector (Vec2 a) where
Vec2 (x1,y1) <+> Vec2 (x2,y2) = Vec2 (x1+x2, y1+y2)
instance (Num a) => VectorMul (Vec2 a) a where
type Result (Vec2 a) a = (Vec2 a)
Vec2 (x,y) <*> a = Vec2 (x*a, y*a)
works :: (Num a) => Vec2 a -> a -> Vec2 a
works a b = a <*> b
このコードは、少なくとも関数のように使用されている場合は機能しているようworks
です。Vec2 (3,4) <*> 5
しかし、 GHCi のような単純な式を入力しようとすると、(Num xx)
型変数があいまいであると報告されます。これは私には奇妙です...この場合、何が欠けていますか? Haskell は、リテラルに対して同じ任意の型を選択して、型式を機能させることができる必要があります (works
関数で行うように)。