Может ли кто-нибудь удалить сахар из этой монады?

Написано в этой удобной нотации, мне это кажется довольно понятным. Но я не могу получить версию обессахаренного с помощью >>= на работу, которая вызывает беспокойство. Может ли кто-нибудь переписать их в расширенной записи, пожалуйста?

Не вложенный

stack1 :: StateT Int Identity ( Int, Int )
stack1 = do
    a <- get 
    put ( a + 1 )
    b <- get
    return ( a, b )

runstack1 :: ( Int, Int )
runstack1 = evalState stack1 11

Вложенные

stack3 :: StateT Int ( StateT String ( StateT String Identity ) ) ( Int, String, String )
stack3 = do
    modify (+10)
    lift $ modify ( ++ " world" )
    lift . lift $ modify ( ++ " word" )
    a <- get
    b <- lift get
    c <- lift . lift $ get
    return ( a, b, c )


runStack3 :: ( Int, String, String )
runStack3 = runIdentity $ evalStateT ( evalStateT ( evalStateT runStack3 1 ) "hello" ) "harro"

Кроме того, сравнивая в сигнатуре runStack1 и runStack3, я могу понять, почему runIdentity необходимо, но может ли кто-нибудь объяснить, почему это так, поскольку и stack1, и stack3 обертывают конструктор Identity?

1 ответ

Решение

Desugared версия вложенного примера:

stack4 :: StateT Int ( StateT String ( StateT String Identity ) ) ( Int, String, String )
stack4 = modify (+10) >>= \_ ->
         (lift $ modify ( ++ " world" )) >>= \_ ->
         (lift . lift $ modify ( ++ " word" )) >>= \_ ->
         get >>= \a ->
         lift get >>= \b -> 
         (lift . lift $ get) >>= \c ->
         return (a,b,c)

В аппликативном стиле:

import Control.Applicative

stack5 :: StateT Int ( StateT String ( StateT String Identity ) ) ( Int, String, String )
stack5 = modify (+10) *> 
         (lift $ modify ( ++ " world" )) *>
         (lift . lift $ modify ( ++ " word" )) *>  
         ((,,) <$> get <*> lift get <*> (lift . lift $ get))

Кроме того, Lambdabot может выполнять автоматическое удаление ошибок, см. Этот вопрос.

Что касается необходимости runIdentityв этом нет ничего загадочного. Вы должны развернуть каждый слой стека монады, чтобы получить значение внутри, и Identity случается в стеке. Теперь State Монада может быть реализована с точки зрения StateT а также Identity, но в этом случае пользователю предоставляется "унифицированный вид", который скрывает внутренний механизм. Если вы проверите исходный код для runState в transformers пакет, вы увидите, что он вызывает runIdentity внутренне.

Другие вопросы по тегам