「サブ」タイプを実現するには、いくつかのオプションがあります。data
1つ目は、試みているように、より多くのタイプを使用することです:
data Car a = Ford (Ford a) | Mercedes (Mercedes a) deriving (Show)
data Ford a = ModelT a | Falcon a deriving (Show) -- different Fords models
data Mercedes a = CClass a | SClass a deriving (Show) -- different Mercedes models
型構築子であることはデータ構築子であることとは異なることに注意しdata Car = .. | Mercedes a
てください. これで、次のような関数を使用できます。Car String
Mercedes "a"
Mercedes
horsepower :: Car a -> Float
horsepower (Ford (ModelT _)) = 1
horsepower (Ford (Falcon _)) = 500
horsepower (Mercedes (CClass _)) = 300
horsepower (Mercedes (SClass _)) = 400
そして、あなたの例は次のようになります:
myfunc :: Show a => Car a -> String
myfunc a = show a ++ " works correctly"
-- myfunc (Ford (ModelT "A")) => Ford (ModelT "A") works correctly
-- myfunc (Mercedes (CClass "b")) => Mercedes (CClass "b") works correctly
このような「サブタイピング」を可能にする別の方法は、型クラスを使用することです (詳細によっては、これがより良いオプションになる場合があります)。例えば
class (Show c) => Car c where
make :: String
model :: c -> String
horsepower :: c -> Float
number_of_seats :: c -> Int
-- etc.
data Ford a = ModelT a | Falcon a deriving (Show)
instance (Show a) => Car (Ford a) where
make = "Ford"
horsepower (ModelT _) = 1
horsepower (Falcon _) = 500
-- etc.
data Mercedes a = CClass a | SClass a deriving (Show)
instance (Show a) => Car (Mercedes a) where
make = "Mercedes"
horsepower (CClass _) = 300
horsepower (SClass _) = 400
-- etc.
あなたの例は次のmyfunc
とおりです。
myfunc :: (Car c) => c -> String
myfunc c = (make `asTypeOf` c) ++ " " ++ show c ++ " works correctly"
-- myfunc (ModelT "A") => Ford ModelT "A" works correctly
-- myfunc (CClass "b") => Mercedes CClass "b" works correctly
function (Ford (Ford "a"))
また、 (またはfunction (CClass "a")
) のような関数を括弧で呼び出さなければならないことに注意してください。