Può qualcuno camminare me con questa funzione Haskell (monade Stato correlate)?
Domanda
tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>= \y ->
return n
Sono confuso su come put (n+1)
ha alcun effetto sul risultato finale di questa funzione a tutti. Sembra che questa funzione dovrebbe tornare allo stato iniziale invariato. Sto cercando di correre attraverso questo nella mia mente, ma io continuo a corto di spazio per tenere le cose a posto. : \
Se qualcuno mi poteva camminare attraverso la valutazione di questa funzione, sarebbe davvero utile.
Soluzione
... Come è mette aggiornamento dello stato in primo luogo? Sembra essere appena seduto lì senza far nulla ...
Ah, ora ho capito la tua domanda. Vi state chiedendo come put
(e get
) funzionano, giusto?
Forse un esempio in JavaScript aiuterà (una lingua con stato mutevole reale):
var s; // mutable state
function get() { return s; }
function put(x) { s = x; }
function tick() {
var n = get();
put(n + 1);
return n;
}
Spero che questo dimostra che, mentre n
non cambia, lo stato interno ancora viene aggiornata. Se si esegue tick()
due volte, lo stato sarà incrementato due volte.
Per tornare a Haskell, ecco la definizione completa di (parti rilevanti) della monade State
:
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)
Ora cercare di ampliare il vostro esempio tick
ulteriormente inlining manualmente >>=
, return
, get
e put
. Speriamo che otterrà più chiaro come funziona Stato.
Altri suggerimenti
Hai perfettamente ragione. Il "risultato" di "funzione" tick
è il valore iniziale dello stato.
Ora, naturalmente, tick
non è la "funzione" reale, ma un calcolo in grado di leggere e scrivere Stato prima di produrre un risultato.
In questo caso, il Stato è aggiornato, ma si sta ancora restituendo il valore originale dello stato:
-- 4 is the inital state
ghci> runState tick 4
(4, 5)
-- 4 is the result of the tick computation, 5 is the updated state
In questo caso, dal momento che non si è mai ispezionare di nuovo lo stato interno tick
, non stai vedendo lo stato modificato. Tuttavia, se qualche altro calcolo avviene dopo tick
, può vedere lo stato aggiornato.
Ad esempio, facendo tick
due volte (la seconda leggerà lo stato aggiornato):
-- 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
potrebbe aiutare a scrivere usando la notazione do
tick :: State Int Int
tick = do
n <- get -- get the state
put (n+1) -- save an incremented state
return n -- return the original state
mentre il put (n+1)
non influisce il risultato del calcolo, si altera lo stato che si svolge all'interno monade stato.