2016-05-19 2 views
1

Думаю, я понимаю, как работает Государственная Монада. Мне удалось написать код, который использует State Monad.State Monad Bind

Я понимаю, как работает экземпляр Монада государства:

instance Monad (State s) where 
return x = State $ \s -> (x,s) 
(State h) >>= f = State $ \s -> let (a, newState) = h s 
            (State g) = f a 
           in g newState 

Этот код работает прекрасно:

type PeopleStack = [String] 

enterClub :: String -> State PeopleStack String 
enterClub name = state $ \xs -> (name ++ " entered club", name:xs) 

leaveClub :: State PeopleStack String 
leaveClub = state $ \(x:xs) -> ("Someone left the club", xs) 

clubAction :: State PeopleStack String 
clubAction = do 
    enterClub "Jose" 
    enterClub "Thais" 
    leaveClub 
    enterClub "Manuel" 

Однако, когда я пытаюсь написать clubAction в функции привязки Я не могу показаться, чтобы заставить его работать.

это то, что я пробовал:

let statefulComputation1 = enterClub "Jose" 
statefulComputation1 :: State PeopleStack String 

runState (statefulComputation1 >>= (enterClub "Manuel") >>= leaveClub) [] 

Я получаю эту ошибку:

<interactive>:13:22: 
Couldn't match type ‘StateT 
         PeopleStack Data.Functor.Identity.Identity String’ 
       with ‘String 
        -> StateT PeopleStack Data.Functor.Identity.Identity a’ 
Expected type: String 
       -> StateT PeopleStack Data.Functor.Identity.Identity a 
    Actual type: State PeopleStack String 
Relevant bindings include 
    it :: (a, PeopleStack) (bound at <interactive>:13:1) 
In the second argument of ‘(>>=)’, namely ‘leaveClub’ 
In the first argument of ‘runState’, namely 
    ‘(state1 >>= leaveClub)’ 

Мой вопрос, как я могу перевести это сделать запись к функции, используя привязку.

ответ

3

Вы должны использовать (>>) вместо (>>=):

runState (statefulComputation1 >> (enterClub "Manuel") >> leaveClub) [] 

(enterClub "Manuel") имеет тип State PeopleStack String(>>=) в то время как требуется функция String -> State PeopleStack a в качестве второго аргумента. Поскольку вы не используете использование результата из statefulComputation1, вы можете комбинировать их с (>>), который игнорирует результат при первом вычислении состояния.

+0

ok. поэтому я могу использовать >>, а затем просто частично применить (enterClub «Manuel»)? Это то, что происходит правильно? –

+1

@JoseMariaLanda - 'enterClub' имеет только один параметр, поэтому' enterClub "Manuel" 'не является частичным приложением. Но да, если у вас есть два значения «State», которые вы хотите запустить последовательно, и вам нужны только эффекты первого, вы можете использовать '>>'. Если вам нужен результат из первого, вы используете '>> =' для создания следующих действий состояния. – Lee

+0

о. Я получаю это сейчас. thanks =) –

2

Каждый элемент на правой стороне оператора связывания (>> =) должен быть лямбда ...., так что это будет работать

runState (statefulComputation1 >>= \_ -> enterClub "Manuel" >>= \_ -> leaveClub) [] 

или, вы можете использовать сокращенную (>>)

runState (statefulComputation1 >> enterClub "Manuel" >> leaveClub) [] 
+1

oh ok. Это то, что, поскольку State Int Int совпадает с \ s -> (Int, Int), я думал, что это была функция, которая потребляла операцию с состоянием. Значит, это должно быть: (\ _ -> s -> (a, s)) вместо этого? –

+0

В значительной степени, кроме того, что это не совсем «то же самое, что», оно завернуто в новый тип. Но да. –

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