2014-09-21 11 views
10

Sto imparando Haskell lavorando attraverso lo Haskell course by Brent Yorgey. Ho appena raggiunto la sezione Monade, e mentre penso di avere (finalmente) una conoscenza decente su come lavorare con le monadi, non capisco come testare il codice che le usa.Test del codice monadico

L'esercizio di questa sezione è di scrivere una simulazione di rischio (semplificata) e richiede un uso intensivo della monade Rand StdGen. In particolare, dobbiamo scrivere la seguente funzione:

type Army = Int 

data Battlefield = Battlefield { attackers :: Army, defenders :: Army } 

battle :: Battlefield -> Rand StdGen Battlefield 

Ci vuole una battaglia iniziale, e viene eseguito una simulazione di come questa battaglia sarebbe andata.

Ho un'implementazione per questo, ma non capisco come testarlo. Non riesco a "capire" i valori all'interno dello restituito da, quindi non posso stamparli nell'interprete GHCI, che è il modo in cui ho testato il mio codice finora. Inoltre non riesco a capire come stampare il risultato di una battaglia in una funzione principale di Haskell, o qualcosa del genere. Come fanno le persone a testare questo tipo di funzioni?

+4

È possibile "ottenere" il risultato di un calcolo casuale utilizzando funzioni come ['evalRand'] (http://hackage.haskell.org/package/MonadRandom-0.1.3/docs/Control-Monad-Random. html) e amici. 'evalRand' prende un 'avvio'' RandomGen' e esegue il calcolo monadico in modo deterministico. –

+1

Fantastico, grazie! Se lo pubblichi come risposta, lo accetterò. – anjruu

risposta

10

È possibile "ottenere" il risultato di un calcolo casuale utilizzando funzioni come evalRand e amici. evalRand prende un 'inizio' RandomGen ed esegue il calcolo monadico in modo deterministico.


Ecco la mia spiegazione non rigoroso-agitando la mano di quello che evalRand è per:

Una delle differenze tra monadi e programmazione imperativa è che una monade è un rappresentazione di un calcolo, non la computazione stessa. In altre parole, quando Haskell valuta un'espressione come a >>= b >>= c (o la notazione equivalente do), è sufficiente mettere insieme i mattoncini Lego, per così dire - il calcolo non ha luogo fino a che esegue la monade usando una funzione come evalRand .

Per un esempio più semplice, pensare a comporre le funzioni insieme. . fornisce una funzione che rappresenta il calcolo eseguito dalle due funzioni che compone. Si ottiene un valore di ritorno da quel calcolo solo quando si chiama effettivamente la funzione con un argomento.

Ecco perché molte delle monade nella libreria standard (con l'eccezione di IO, che viene eseguita dal sistema di runtime) forniscono una funzione "botola" come evalRand. È come in realtà usi il il calcolo che hai appena definito nel tuo codice monadico.

+4

Questo è un modo utile di pensare a molte monadi, ma è * non * vero per le monadi in generale. La lista monade non differisce il calcolo fino a quando non si chiama una funzione "botola" (tranne che per la pigrizia). Sono solo le monadi che forniscono accesso implicito ad un tipo di ambiente che funziona necessariamente nel modo in cui descrivi, e questo perché ad es. un 'Rand StdGen Int' rappresenta un" intero probabilistico ", che necessita di un' StdGen' da fornire per selezionare un 'Int' concreto da tutti i valori che potrebbe essere. – Ben

+1

Hai perfettamente ragione, ovviamente. Grazie per il commento. Fornisce alcuni importanti contesti ed equilibri alla mia descrizione qualitativa. –

Problemi correlati