Монад фасад для MonadState в Haskell
Предыстория: я создаю игру с монадой с сохранением состояния для чтения и записи изменений в глобальном состоянии игры.
Я хотел бы разделить мою игру на компоненты, такие как "Персонажи", предоставляя доменным способом взаимодействия этих компонентов с глобальным состоянием. В идеале это может быть определение конкретных действий в форме MonadState Character m => m a
что я мог бы использовать, но каждый такой m a
будет принимать изменения на родителя (глобальное состояние).
Я искал возможность конвертировать монады состояний или предоставлять интерфейс из одной монады состояний в другую, но конкретный язык для этого выходит за рамки моих знаний. Я также уже использую линзы, и мне интересно, могу ли я что-нибудь с ними сделать.
РЕДАКТИРОВАТЬ:
Я хотел бы иметь возможность сделать что-то вроде moveCharacter :: MonadState Character m => Int -> Int -> m ()
и есть что выполнить move :: MonadState World m => Int -> Int -> m ()
внутри. В основном, абстрагируя мир от специфики персонажа.
Спасибо!
2 ответа
Похоже, вы ищете Zoom
, который позволяет преобразовать действие с состоянием на вид объектива в действие с состоянием на источник объектива.
На самом деле вам нужны 2 функции преобразования: одна для извлечения персонажа из мира и другая для изменения мира с помощью измененного персонажа. Вы можете соединить их так:
extractCharacter :: World -> Character
extractCharacter = error "Tried to call placeholder function"
replaceCharacter :: World -> Character -> World
replaceCharacter = error "Tried to call placeholder function"
runCharacterSubroutine :: (Functor m) =>
StateT Character m a -> StateT World m a
runCharacterSubroutine act = StateT $ \w ->
fmap (\(a,c') -> (a,replaceCharacter w c')) $
runStateT act (extractCharacter w)
В вашей игре вы, вероятно, хотите что-то более сложное, но это просто вопрос добавления дополнительного параметра в extractCharacter
а также replaceCharacter
Обратите внимание, что функция, которую я дал, работает, только если StateT
находится на вершине стека трансформаторных монад. Если это не так: вам придется использовать mmorph
пакет