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
Другие вопросы по тегам