Я не вижу проблем, требующих только ограничений на функции.Проблема, я полагаю, в том, что ваша структура данных больше не моделирует именно то, что вы намереваетесь.С другой стороны, если вы в первую очередь думаете об этом как о структуре данных, то это должно иметь меньшее значение.
Я чувствую, что не обязательно все еще хорошо разбираюсь в этом вопросе, и этопримерно настолько неопределенно, насколько это возможно, но мое эмпирическое правило, как правило, состоит в том, что классы типов - это вещи, которые подчиняются законам (или смыслу модели), а типы данных - это вещи, которые кодируют определенное количество информации.
Когда мы хотимСложное поведение слоев, я обнаружил, что классы типов начинаются заманчиво, но могут быстро причинять боль, а переключение на передачу словаря делает вещи более простыми.То есть, когда мы хотим, чтобы реализации были совместимыми, мы должны вернуться к унифицированному типу словаря.
Это займет два, немного расширив конкретный пример, но все же просто отсортироваввращающихся идей ...
Предположим, мы хотим смоделировать вероятностные распределения по реалам.На ум приходят два естественных представления.
A) Управляемый типами
class PDist a where
sample :: a -> Gen -> Double
B) Управляемый словарем
data PDist = PDist (Gen -> Double)
Первое позволяет нам делать
data NormalDist = NormalDist Double Double -- mean, var
instance PDist NormalDist where...
data LognormalDist = LognormalDist Double Double
instance PDist LognormalDist where...
Последний позволяет нам делать
mkNormalDist :: Double -> Double -> PDist...
mkLognormalDist :: Double -> Double -> PDist...
В первом мы можем написать
data SumDist a b = SumDist a b
instance (PDist a, PDist b) => PDist (SumDist a b)...
, во втором мы можем просто написать
sumDist :: PDist -> PDist -> PDist
Так каковы компромиссы?Управляемый типом классов позволяет нам указать, какие дистрибутивы нам даны.Компромисс состоит в том, что мы должны явно построить алгебру распределений, включая новые типы для их комбинаций.Управляемый данными не позволяет нам ограничивать распределение, которое мы даем (или даже если они правильно сформированы), но взамен мы можем делать все, что захотим.
Более того, мы можем написать1032 * относительно легко, но мы должны пройти через некоторое беспокойство, чтобы сделать эквивалент для подхода класса типов.
Так что это, в некотором смысле, типизированный / нетипизированный статический / динамический компромисс на другом уровне.Тем не менее, мы можем изменить его и утверждать, что класс типов, наряду с соответствующими алгебраическими законами, задает семантику распределения вероятностей.И тип PDist действительно можно сделать экземпляром класса типов PDist.Между тем, мы можем смириться с использованием типа PDist (а не класса типов) практически везде, в то время как считает его как iso для башни экземпляров и типов данных, необходимых для более "богатого" использования класса типов.
Фактически, мы даже можем определить базовую функцию PDist в терминах функций класса типов.то есть mkNormalPDist m v = PDist (sample $ NormalDist m v)
Так что в пространстве дизайна есть много места для скольжения между двумя представлениями по мере необходимости ...