Pour tester mes compétences à Haskell, j'ai décidé que je voulais mettre en œuvre le tout premier jeu que vous trouverez dans terres de Lisp em> / royaume de raquette em>. Le "devine mon numéro" em> jeu. Le jeu s'appuie sur l'état mutable à exécuter, car il doit constamment mettre à jour les limites supérieure et inférieure du programme à domicile sur la valeur de la valeur de l'utilisateur. Cela va un peu comme ceci: P> XXX PRE> Maintenant, ce type de chose (à ma connaissance) n'est pas entièrement possible dans HASKELLL, appelant une fonction de la part de la réplique qui modifie l'état mutable global, puis imprime le résultat immédiatement après, comme il enfreint le principe de l'immutabilité. Par conséquent, toute l'interaction doit vivre à l'intérieur d'un Je n'arrive pas à pouvoir envelopper mon esprit autour de la combinaison du Voici ce que j'ai jusqu'à présent: p> Comment puis-je combiner Remarque: je suis conscient que Cela peut probablement être atteint sans l'utilisation de l'état du tout; Mais je veux que cela reste fidèle à l'original p> p> io code> et / ou
état code> monad. Et c'est là que je suis coincé. p>
io code> monad et de l'état
code> monade, donc je peux obtenir une entrée, imprimer Résultats et modifier l'état, tous dans la même fonction. P>
type Bound = (Int, Int) -- left is the lower bound, right is the upper
initial :: Bound
initial = (1, 100)
guess :: Bound -> Int
guess (l, u) = (l + u) `div` 2
smaller :: State Bound ()
smaller = do
bd@(l, _) <- get
let newUpper = max l $ pred $ guess bd
put $ (l, newUpper)
bigger :: State Bound ()
bigger = do
bd@(_, u) <- get
let newLower = min u $ succ $ guess bd
put $ (newLower, u)
io code> et
état code> d'une manière élégante pour y parvenir? p>
4 Réponses :
Voici une solution à l'aide du transformateur code> statut code>. Points notables:
getline code> au lieu d'utiliser le repl. li>
- Il lit beaucoup comme un programme impératif, sauf que vous devez ajouter
liftidio code> à n'importe quelle action IO. LI>
- Vous exécutez la boucle avec
runstatet code> où vous fournissez également l'état initial. Li>
ol> Le programme: p> xxx pré> p>
Voulez-vous dire que vous voulez interagir avec l'utilisateur via la RÉPP? Vous ne pouvez pas utiliser votre code existant car une signature comme lié à l'état () code> ne permet aucun IO d'être effectué et que vous ne pouvez pas exécuter
plus grand code> et
plus petit code> à partir du repliant - ça n'a aucun sens. Vous pouvez appeler
Runstate Bigger code> à partir de la RÉPL, mais vous devez également fournir l'état.
Vous n'avez pas à utiliser l'état monade du tout dans cet exemple. Voici un exemple qui transmet l'état sous forme de paramètre: sinon, le concept que vous recherchez est monad transformers em>. Par exemple, utilisation du statut: p> voir ceci chapitre du monde réel Haskell pour un didacticiel sur le sujet des transformateurs de Monad. P> P>
J'aimerais pouvoir utiliser mon code existant si possible
@ElectricCoffee: Et si votre code existant est faux?
Une bonne programmation consiste à la séparation des préoccupations, ayant une fonction qui fait que tout ce que les fonctions réutilisables plus petites est généralement toujours meilleure. Ce que j'ai à l'heure actuelle se comporte la façon dont je m'attends, ce sont les bits restants qui doivent tomber en place
@ElectricCoffee J'ai modifié l'exemple du transformateur pour utiliser des adaptations de votre code> plus petit code> plus grand code> fonctions. J'espère que vous voyez comment cela compose. L'utilisation de votre code d'origine n'est pas possible.
Vous pouvez combiner différentes monades à l'aide de MONAD Transformers - dans ce cas alors vous pouvez écrire une fonction pour exécuter le jeu donné un paramètre d'état: p> Vous utilisez Enfin, vous pouvez exécuter le jeu en utilisant statut code>. Vous pouvez utiliser votre code existant en modifiant les signatures de type pour utiliser
statut code>:
lifidio code> pour soulever un
IO code> Action dans le
statuète liée IO code> monad, permettant Vous inviter à entrer et lire la ligne suivante. P>
runstatet code>: p>
runStateT game initial
Très beau, très simple, très élégant! C'est exactement ce que j'avais à l'esprit
ne serait-il pas préférable d'écrire impression $ $ S S code> au lieu de
postStrln (show. suppose $ s) code>?, les appels code> impression code> " code> montrer code> interne quand même
Ce que vous demandez est en quelque sorte possible ...
$ ghci guess.hs GHCi, version 7.9.20141202: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Main ( guess.hs, interpreted ) Ok, modules loaded: Main. *Main> (guess, smaller, bigger) <- makeGame *Main> guess 50 *Main> smaller 25 *Main> bigger 37 *Main>
Attendez, c'est donc l'ordinateur qui devine le nombre?
@Jefffrey Oui, dans la version LISP, l'ordinateur devine, pas la personne; C'est pourquoi il est tellement plus amusant de mettre en œuvre
Voir aussi Gestion de l'état .