2010-08-05 12 views
4

Итак, я пишу игру в Haskell, и я выражаю очередь игрока как серию изменяющих состояние функций, которые коррелируют с различными фазами поворота. Первоначально это выглядело примерно так:Государственные монады: торговля одним шаблоном для другого?

let game' = phase1 game 
    game'' = phase2 game' 
-- etc. 

Главный кандидат на государственную монархию, не так ли? Это приводит к более элегантно:

do 
    phase1 
    phase2 
-- etc. 

Однако, то кажется, что я должен изменить phase1, phase2 и др начать с шаблонным «государство получает» шаг:

phase1 = get >>= \game -> -- ... 

Я m надеясь, что есть способ абстрагировать это, поэтому я могу избежать шаблона как у вызывающего, так и у вызывающего. Я просто слишком новичок, чтобы знать, что это такое (это мой первый настоящий проект Haskell). Любой совет?

+4

'.... фаза 3. фаза 2 . phase1 $ game'? – kennytm

ответ

8

Ну, это еще не совсем монадично. Это главный кандидат на моноид Endo. Это приводит к более элегантной

game = mconcat [ phase1, phase2, ... ] 

И каждая фаза написано:

phase1 = Endo $ \game -> ... 

Вы бы перейти к монады, если вам необходимо, чтобы вернуть некоторые дополнительные данные вместе с новым состоянием в каждой фазе. В этом случае простая функция сделает ваш шаблонный более терпимым:

phase :: (GameState -> GameMonad a) -> GameMonad a 
phase f = f =<< get 

А потом фаза написано:

phase1 = phase $ \game -> do ... 

Но если вы хотите использовать состояние, вы, вероятно, придется дайте ему имя (если вы не можете ограничить pointfreeness, скажем, используя gets или data-accessor), и в этом случае вы не можете получить много терпения, кроме функции и лямбда.

+1

Или 'game = mconcat $ map Endo [phase1, phase2, ...]' и 'phase1 game = ...' –

+1

'appEndo. mconcat. map Endo = foldr (.) id' Я предлагаю использовать «Endo» больше как абстракцию, а не просто метод составления списка функций. Я не знаю, что я имею в виду под этим: -P – luqui