Ответ 1
что это ограничивает, поэтому вы не можете сопоставлять шаблон конструкторам с параметром ограничения класса типа?
Когда вы сопоставляете шаблон с явным конструктором, вы фиксируете конкретное представление типа данных. Этот тип данных не используется для всех экземпляров класса, поэтому просто невозможно написать функцию, которая работает для всех экземпляров таким образом.
Вместо этого вам нужно связать различные типы поведения, которые вы хотите с каждым экземпляром, например:
class C a where
toString :: a -> String
draw :: a -> String
instance C MyType1 where
toString v = "MyType1"
draw (MyObj11 x) = "11"
draw (MyObj12 x y) = "12"
instance C MyType2 where
toString v = "MyType2"
draw (MyObj22 x y) = "22"
data MyType1 = MyObj11 Int | MyObj12 Int Int
data MyType2 = MyObj21 Int | MyObj22 Int Int
test :: C a => a -> String
test x = draw x
Теперь ветки вашей исходной функции test
распределены между экземплярами.
Некоторые альтернативные трюки включают использование связанных с классом типов данных (где вы доказываете компилятору, что тип данных является общим для всех экземпляров) или просматривать шаблоны (что позволяет обобщать соответствие шаблонов).
Просмотр шаблонов
Мы можем использовать шаблоны представления для очистки соединения между сопоставлением шаблонов и экземплярами экземпляров класса, немного, что позволяет нам приближать соответствие шаблонов между экземплярами путем сопоставления шаблонов в общем типе.
Вот пример, где мы пишем одну функцию с двумя случаями, которая позволяет нам сопоставлять шаблон с чем-либо в классе.
{-# LANGUAGE ViewPatterns #-}
class C a where
view :: a -> View
data View = One Int
| Two Int Int
data MyType1 = MyObj11 Int | MyObj12 Int Int
instance C MyType1 where
view (MyObj11 n) = One n
view (MyObj12 n m) = Two n m
data MyType2 = MyObj21 Int | MyObj22 Int Int
instance C MyType2 where
view (MyObj21 n) = One n
view (MyObj22 n m) = Two n m
test :: C a => a -> String
test (view -> One n) = "One " ++ show n
test (view -> Two n m) = "Two " ++ show n ++ show m
Обратите внимание, как синтаксис ->
позволяет нам вернуться к правильной функции view
в каждом экземпляре, просматривая кодировку пользовательского типа данных для каждого типа, чтобы сопоставить соответствие ему.
Задача проектирования состоит в том, чтобы придумать тип вида, который отображает все варианты поведения, которые вас интересуют.
В исходном вопросе вы хотели, чтобы у каждого конструктора было другое поведение, поэтому на самом деле нет причин использовать тип представления (диспетчеризация непосредственно к этому поведению в каждом экземпляре уже работает достаточно хорошо).