Quelqu'un peut-il me promener à travers cette fonction Haskell (monade État lié)?
Question
tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>= \y ->
return n
Je suis confus quant à la façon dont put (n+1)
a un effet sur le résultat final de cette fonction du tout. Il semble que cette fonction doit retourner l'état initial inchangé. Je suis en train de courir à travers cela dans mon esprit, mais je continue à manquer de place pour maintenir les choses en place. : \
Si quelqu'un pouvait me promener à travers l'évaluation de cette fonction, il serait vraiment utile.
La solution
... Comment met la mise à jour de l'état en premier lieu? Il semble juste être assis là sans rien faire ...
Ah, je comprends maintenant votre question. Vous vous demandez comment put
(et get
) fonctionnent, droit?
Peut-être un exemple en JavaScript contribuera (une langue avec l'état mutable réelle):
var s; // mutable state
function get() { return s; }
function put(x) { s = x; }
function tick() {
var n = get();
put(n + 1);
return n;
}
J'espère que cela montre que, alors que n
ne change pas, l'état interne sera toujours mise à jour se. Si vous exécutez tick()
deux fois, l'état sera incrémenté deux fois.
Pour revenir à Haskell, voici la définition complète de (les parties pertinentes) du 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)
Maintenant, essayez d'élargir votre exemple tick
encore manuellement par inline >>=
, return
, get
et put
. Espérons que cela va obtenir plus de comprendre comment fonctionne l'Etat.
Autres conseils
Vous êtes tout à fait raison. Le « résultat » de « fonction » tick
est la valeur initiale de l'état.
Maintenant, bien sûr, tick
n'est pas la « fonction » réel, mais un calcul qui peut lire et écrire état avant de produire un résultat.
Dans ce cas, le État est mis à jour, mais vous êtes toujours revenir la valeur initiale de l'état:
-- 4 is the inital state
ghci> runState tick 4
(4, 5)
-- 4 is the result of the tick computation, 5 is the updated state
Dans ce cas, puisque vous n'êtes jamais inspecter l'état à nouveau à l'intérieur tick
, vous ne voyez pas l'état a changé. Toutefois, si un autre calcul qui se passe après tick
, il peut voir l'état mis à jour.
Par exemple, faire tick
deux fois (la deuxième lira l'état mis à jour):
-- 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
il pourrait aider à écrire en utilisant la notation 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
alors que le put (n+1)
n'a pas d'impact le résultat du calcul, il ne modifie l'état qui est tenue dans la monade de l'Etat.