2017-02-10 16 views
2

Я ищу, чтобы пройти государственную монады через следующие функции:Связывание вычислений с государственной монадой?

e1 :: Int -> (Bool, Int) 
e1 el 
    | el > 100   = (True, el) 
    | otherwise   = (False, 0) 

e2 :: Int -> (Bool, Int) 
e2 el 
    | el > 200   = (True, el) 
    | otherwise   = (False, 0) 

e3 :: Int -> (Bool, Int) 
e3 el 
    | el > 300   = (True, el) 
    | otherwise   == (False, 0) 

implementor :: State Bool Int 
implementor = state e1 ... 

main = do 
    print $ runState implementor 10 

В настоящее время runState передается в State s a (implementor) и значение (10), а затем возвращая кортеж из e1.

Однако я хотел бы связать эти операции вместе, такие как:

state e1 >>= e2 >>= e3 

e1 пройдет его State Bool Int в e2, который будет работать на Int (через el), а затем передать это в результате State Bool Int к e3, который, опять же, будет работать на Int в этом состоянии.

Я нашел экземпляр Monad государства очень запутанным, после this руководства:

instance Monad (State s) where 
    return :: state $ \s -> (s, a)--this is returning a State which contains function (s -> (s, a)) 
    m >>= k = state $ \s -> let (a, s') = runState m s --? 
        in runState (k a) s' 

Я не понимаю, что это пример привязки делает и как использовать это, чтобы связать e1, e2 и e3 вместе?

+1

Вы ищете «состояние e1 >> состояние e2 >> состояние e3'? – Zeta

+0

@Zeta Я добавил к своему вопросу для ясности –

+1

Err, 'state e1' is __not__ a State Bool Int', но' State Int Bool'. – Zeta

ответ

5

Если вы используете state :: (s -> (a, s)) -> State s a на e1, вы в конечном итоге с State Int Bool:

state e1 :: State Int Bool 

То есть то, что действует над государством (в данном случае Int) и дает Bool в результате использования, что государство. Поэтому, если мы хотим использовать e1, e2 и e3 друг за другом в отслеживанием состояния вычислений, мы могли бы использовать их с do -notation:

allThree :: State Int() 
allThree = do 
    firstBool <- state e1 
    secondBool <- state e2 
    thirdBool <- state e3 
    return thirdBool 

Однако, если мы будем игнорировать первые два Bool с, мы можем просто удалить привязок:

allThree :: State Int Bool 
allThree = do 
    state e1 
    state e2 
    state e3 

и теперь мы можем переписать do -notation с >> и >>=. Мы в конечном итоге с

allThree :: State Int Bool 
allThree = state e1 >> state e2 >> state e3 

Что касается, как это работает, давайте посмотрим на >>=

m >>= k = state $ \s -> let (a, s') = runState m s 
          in runState (k a) 

И m >> k является m >>= const k. Так что давайте посмотрим, что state e1 >> state 2 делает:

state e1 >> state e2 
    = state e1 >>= const (state e2) 
    = state $ \s -> let (a, s') = runState (state e1) s in runState (const (state e2) a) s' 
    -- simplify runState (state e1) s to e1 s 
    = state $ \s -> let (a, s') = e1 s in runState (const (state e2) a) s' 
    -- use "const" 
    = state $ \s -> let (a, s') = e1 s in runState (state e2) s' 
    -- again simplify runState (state e2) s' to e2 s' 
    = state $ \s -> let (a, s') = e1 s in e2 s' 

Таким образом, следующие условия одинаковы:

stateful s = runState (state e1 >> state e2) s -- use above to show that 
stateless s = let (_, s') = e1 s 
       in e2 s' 

Теперь, почему я в состоянии использовать изменение runState (state f) для f?Поскольку определение State довольно скучное:

-- simplified, modern versions use a more sophisticated approach! 
newtype State s a = State { runState :: s -> (a, s) } 

То есть State FUL действие является то, что принимает состояние и возвращает новую вместе со значением. state функция, таким образом, довольно просто:

state :: (s -> (a, s)) -> State s a 
state = State 

А поскольку runState (State f) является f, runState (state f) также `Г'.

Поэтому можно было бы написать Monad экземпляру немного иначе:

instance Monad (State s) where 
    (State e1) >>= f = State e3 
    where 
     e3 s = let (a, s') = e s 
        (State e2) = f a 
       in e2 s' 

Помните, что >>= ожидает функцию, которая принимает что-то и возвращает другое действие, в то время как >> можно использовать для цепи действий друг за другом ,