Я пересматривал часть кода, который я написал, чтобы сделать комбинаторный поиск несколько месяцев назад, и заметил, что существует альтернативный, более простой способ сделать то, что я ранее достиг с классом типа.
В частности, я ранее имел тип типа для типа проблем поиска, которые имеют состояния типа s
, действия (операции над состояниями) типа a
, начальное состояние, способ получения списка пар (действие, состояние) и способ проверки, является ли состояние решением или нет:
class Problem p s a where
initial :: p s a -> s
successor :: p s a -> s -> [(a,s)]
goaltest :: p s a -> s -> Bool
Это несколько неудовлетворительно, так как для этого требуется расширение MultiParameterTypeClass и обычно требуется FlexibleInstances и, возможно, TypeSynonymInstances, когда вы хотите создавать экземпляры этого класса. Он также загромождает ваши сигнатуры функций, например.
pathToSolution :: Problem p => p s a -> [(a,s)]
Сегодня я заметил, что могу полностью избавиться от класса и использовать вместо него следующие строки
data Problem s a {
initial :: s,
successor :: s -> [(a,s)],
goaltest :: s -> Bool
}
Это не требует каких-либо расширений, функции подписи выглядят лучше:
pathToSolution :: Problem s a -> [(a,s)]
и, самое главное, я обнаружил, что после рефакторинга моего кода, чтобы использовать эту абстракцию вместо класса типа, я остался на 15-20% меньше строк, чем раньше.
Самая большая победа была в коде, который создавал абстракции с использованием класса типа - ранее мне приходилось создавать новые структуры данных, которые сложнее завернули старые, а затем превратили их в экземпляры класса Problem
(который требовал больше языковых расширений) - множество строк кода, чтобы сделать что-то относительно простое. После рефакторинга у меня было несколько функций, которые сделали именно то, что я хотел.
Теперь я просматриваю остальную часть кода, пытаясь определить экземпляры, где я могу заменить типы классов типами и сделать больше выигрышей.
Мой вопрос: в какой ситуации будет работать этот рефакторинг не? В каких случаях лучше всего использовать класс типа, а не тип данных, и как вы можете распознать эти ситуации раньше времени, поэтому вам не нужно проходить дорогостоящий рефакторинг?