2015-10-26 4 views
1

Фон: Я создаю игру с монашеской монадой для чтения и записи изменений в глобальном состоянии игры.Monad фасад для MonadState в Haskell

Я хотел бы разделить свою игру на компоненты, такие как «Персонажи», предоставляя особый способ взаимодействия этих компонентов с глобальным состоянием. В идеале это может быть определено конкретными действиями формы MonadState Character m => m a, которую я мог бы использовать, но каждый такой m a мог бы внести изменения в родительское (глобальное состояние).

Я искал для преобразования между государственными монадами или предоставления интерфейса от одной государственной монады к другой, но конкретный язык для этого выходит за рамки моего знания. Я также уже использую объективы, и мне интересно, смогу ли я с ними что-то сделать.

EDIT:

Я хотел бы быть в состоянии сделать что-то вроде moveCharacter :: MonadState Character m => Int -> Int -> m()

и есть, которые выполняют move :: MonadState World m => Int -> Int -> m() внутри. В принципе, абстрагирование мировой специфики от характера.

Спасибо!

ответ

3

Похоже, что вы ищете Zoom, что позволяет конвертировать действие с состоянием на вид объектива в состояние, действующее на источник объектива.

+0

Я изучил использование Zoom, но я не уверен, соответствует ли это моему предыдущему варианту использования выше. Я не уверен, как установить это, чтобы я мог построить монаду монада-монаха, но быть связан с монадическим действием в мире. –

+0

Ну ... вы не можете делать то, что вы просите. Любое состояние, к которому вы хотите иметь доступ, должно быть, по крайней мере, доступно в соответствии с типом подписи - вы не можете лгать о том, к какому состоянию вам нужен доступ! Если вашему действию нужен доступ к мировому состоянию, ну, по golly, тип должен будет сказать, что он может получить доступ к мировому состоянию. –

+0

Hrm. В этом есть смысл. То, что я пытаюсь достичь, не позволяет персонажному коду быть способным совершать несанкционированные изменения в родительском состоянии. Моим другим подходом может быть создание некоторого типа данных, когда изменение родительского состояния является конструктором данных (например, «данные STDiff = Move Int Int | ...») –

0

Вам действительно нужны 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

 Смежные вопросы

  • Нет связанных вопросов^_^