Здравствуйте, уважаемые коллеги. У меня назрел вопрос, на который я так и не смог пока найти ответа удовлетворяющего меня полностью, поэтому я обращаюсь к вам.
Завязка стандартная: предположим, мы разрабатываем игру, где присутствуют и взаимодействуют объекты множества различных типов, такие кик игрок, NPC, различное движимое и недвижимое имущество. Мы хотим сделать сделать архитектуру гибкой, где каждый объект сам определяет свою реакцию в ответ на внешние события. Другое важное требование: архитектура должна быть расширяемой, если я хочу добавить новый объект с его уникальными свойствами и поведением, то в идеале я просто должен написать новый модуль и положить его в папку с исходниками (а еще лучше загрузить из динамической библиотеки, наподобие плагина).
Вопрос: каков наилучший путь реализации подобной архитектуры на Haskell в соответствии с его идеологией?
В классическом ООП это делается без особых проблем, достаточно лишь определить общий интерфейс для объекта, где будет возможность вызвать код объекта в ответ на предопределенные события:
interface IGameObject
{
void Move(World world, Direction dir);
void Attack(World world, GameObject victim);
void Take(World world, GameObject what);
void Drop(World world, GameObject what);
// ... etc
}
Соответственно, в плагине мы реализуем логику объекта и просто добавляем его в мир, так что движок ничего не знает о его фактической реализации.
class MyObject : IGameObject
{
...
}
world.AddObject(new MyObject());
Все абстрактно, код независим, ляпота.
Теперь переходим к Хаскеллю.
При попытке реализовать подобную архитектуру в лоб, мы натыкаемся на множество проблем, большинство из них уже описано на haskellwiki. Алгебраические типы тут не подходят явно. Экзистенциальные классы типов? Общее мнение о них, как об антипаттерне, но подобную задачу они решают, на мой текущий взгляд, наиболее адекватно, правда за счет существенного усложнения кода. Структуры с замыканиями скорее всего потребуют реализации единого всеобъемлющего типа данных, содержащего атрибуты от всех возможных разновидностей объектов, что тоже неприемлемо.
Что посоветуете? Разрешима ли вообще подобная задача в Хаскелле? Может быть проблема находится в изначальном списке требований? Направьте на путь истинный.