Pergunta

tick :: State Int Int
tick = get >>= \n ->
       put (n+1) >>= \y ->
       return n

Estou confuso sobre como put (n+1) tem algum efeito no resultado final dessa função. Parece que essa função deve retornar o estado inicial inalterado. Estou tentando passar por isso em minha mente, mas continuo saindo fora de espaço para manter as coisas no lugar. :

Se alguém pudesse me levar pela avaliação dessa função, seria realmente útil.

Foi útil?

Solução

... Como é a atualização do estado em primeiro lugar? Parece apenas estar sentado lá não fazendo nada ...

Ah, agora eu entendo sua pergunta. Você está se perguntando como put (e get) Trabalho, certo?

Talvez um exemplo no JavaScript ajude (um idioma com estado mutável real):

var s; // mutable state
function get() { return s; }
function put(x) { s = x; }

function tick() {
    var n = get();
    put(n + 1);
    return n;
}

Espero que isso ilustre que, enquanto n Não muda, o estado interno ainda será atualizado. Se você executar tick() Duas vezes, o estado será incrementado duas vezes.

Para voltar a Haskell, aqui está a definição completa de (as partes relevantes) do State Mônada:

newtype State s a = State { runState :: s -> (a, s) }

instance Monad (State s) where
    return a = State $ \s -> (a, s)
    m >>= k  = State $ \s -> let
        (a, r) = runState m s
        in runState (k a) r

get   = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)

Agora tente expandir o seu tick Exemplo ainda mais adiante manualmente >>=, return, get e put. Espero que fique mais claro como o estado funciona.

Outras dicas

Você está completamente certo. O resultado de tick "Função" é o valor inicial do estado.

Agora, claro, tick não é a verdadeira "função", mas um cálculo que pode ler e escrever Estado antes de produzir um resultado.
Neste caso, o Estado é atualizado, mas você ainda está retornando o valor original do estado:

-- 4 is the inital state
ghci> runState tick 4
(4, 5)
-- 4 is the result of the tick computation, 5 is the updated state

Nesse caso, já que você nunca mais está inspecionando o estado dentro tick, você não está vendo o estado alterado. No entanto, se algum outro cálculo acontecer depois tick, pode ver o estado atualizado.

Por exemplo, fazendo tick duas vezes (o segundo lerá o estado atualizado):

-- 4 is the inital state
ghci> runState (tick >> tick) 4
(5, 6)
-- 5 is the result of the tick computation executed twice,
-- 6 is the updated state

Pode ajudar a escrever usando do notação

tick :: State Int Int
tick = do
    n <- get    -- get the state
    put (n+1)   -- save an incremented state
    return n    -- return the original state

enquanto o put (n+1) Não afeta o resultado do cálculo, ele altera o estado que é mantido dentro da Mônada do Estado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top