Я новичок в Haskell, и у меня возникли проблемы с монадой State.
Я создал следующие типы. 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
Это может быть повреждение, наносимое существу, увеличение силы существа, в общем, что угодно. Возможность чего угодно заставила меня подумать, что монада State была хорошим выбором. Я принимаю существо в его исходном состоянии, выполняю некоторую модификацию и возвращаю исходное состояние и новое состояние в виде кортежа.
Исходное состояние может быть:
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
, но мой мозг зацикливается на типах.
Какой должна быть хорошая реализация?
Creature
Monoid
? - person Bergi   schedule 26.05.2017applyChanges
не принимает существо в его исходном состоянии. - person Bergi   schedule 26.05.2017Creature -> Creature
, и тогда вашу функциюapplyChanges :: [Creature -> Creature] -> Creature -> Creature
очень легко реализовать:applyChanges = foldr (.) id
- person amalloy   schedule 26.05.2017State
может быть в некотором смысле преждевременным, но я бы все равно это сделал, потому что сразу могу придумать причины, по которым вы захотите. 1. Если вы хотите получить не только конечное состояние, но и список промежуточных состояний. Вы можете сделать это с помощьюscanl
, но если вы начнете сState
, это действительно естественно. 2. Вы хотите добавить некоторые другие эффекты. Если вы начинаете сState
, вам нужно всего лишь переключиться наStateT
для соответствующего базового типа действия. - person dfeuer   schedule 26.05.2017State Creature a
, где значение состояния — это то, что вы действительно хотите получить в результате (через execState), а не монадическое значение, которое вы получили бы от evalState, верно? Это, безусловно, имеет для меня некоторый смысл, ноState Creature Creature
кажется слишком конкретным, требуя, чтобы каждое преобразование заканчивалось наget
, чтобы перевести состояниеCreature
в монадическое значение.State Creature ()
выглядит более разумным в качестве цели для составления списка преобразований с отслеживанием состояния. - person amalloy   schedule 26.05.2017State Creature ()
, наверное, правильное место для начала. - person dfeuer   schedule 26.05.2017Data.Foldable
), этоtraverse_
и (реже)sequenceA_
. Вскоре вас заинтересуют обходыtraverse
иsequenceA
. - person dfeuer   schedule 26.05.2017