Haskell - Как бы я управлял списком государственных монад?
Я немного новичок в Хаскеле, и у меня возникли проблемы с государственной монадой.
Я создал следующие типы.Stat a
для него создан моноид, функтор, аппликативный и монадный экземпляры.
"Основной" тип в моей программе - существо, и у него много аргументов:
data Creature = Creature {
strength :: Stat Integer,
dexterity :: Stat Integer,
...
}
data Stat a = Stat {
modifiers :: [StatModifier],
stat :: a
}
data StatModifier = StatModifier {
modifierType :: ModifierType,
value :: Integer
}
data ModifierType =
Enhancement
| Morale
| ...
Есть много вещей, которые могут случиться с существом. Я решил представить эти вещи с государственной монадой:
anyPossibleChange :: State Creature Creature
Это может быть урон, нанесенный существу, увеличение силы существа, в основном чего угодно. Возможность чего-либо заставила меня думать, что государственная монада была хорошим выбором здесь. Я приму существо в его первоначальном состоянии, выполню некоторую модификацию и верну исходное состояние и новое состояние в кортеже.
Исходное состояние может быть:
Creature {
strength = Stat [] 10,
dexterity = Stat [] 10
}
Конечное состояние может быть:
Creature {
strength = Stat [StatModifier Enhancement 2] 10,
dexterity = Stat [StatModifier Enhancement 4, StatModifier Morale 2] 10
}
Я хотел бы составить список всех изменений, через которые должно пройти существо, а затем провести существо через все эти изменения.
Это подпись, которую я имел в виду, но у меня возникают проблемы с реализацией. Я открыт для того, чтобы быть другим.
applyChanges :: Creature -> [State Creature Creature] -> Creature
Я чувствую, что должен быть в состоянии сделать это со сгибом, возможно, FoldM
но мой мозг зацикливается на типах.
Какой будет хорошая реализация?
1 ответ
State Creature Creature
неправильный тип для такого рода вычислений. Как вы видели, с этим можно обойтись, но это усложняет ситуацию, потому что вы на самом деле не заботитесь о переменной состояния! Вы просто используете его для хранения исходного ввода функции... но затем выбрасываете его в applyChanges
,
Тип, с которым было бы намного легче работать, Creature -> Creature
и затем, если у вас есть список таких функций, которые вы хотите применить, вы просто хотите составить их все, что вы можете сделать с помощью сгиба:
applyChanges :: [Creature -> Creature] -> Creature -> Creature
applyChanges = foldr (.) id