Domanda

ho passato alcuni tutorial su monade Stato e penso che ho avuto l'idea.

Per esempio, come in questo bel tutorial :

import Data.Word

type LCGState = Word32

lcg :: LCGState -> (Integer, LCGState)
lcg s0 = (output, s1) 
  where s1 = 1103515245 * s0 + 12345
        output = fromIntegral s1 * 2^16 `div` 2^32


getRandom :: State LCGState Integer
getRandom = get >>= \s0 -> let (x,s1) = lcg s0
                           in put s1 >> return x

OK, in modo da poter usare getRandom:

*Main> runState getRandom 0
(0,12345)
*Main> runState getRandom 0
(0,12345)
*Main> runState getRandom 1              
(16838,1103527590)

Ma ho ancora bisogno di passare il seme al PRNG ogni volta che lo chiamo io. So che il PRNG disponibili in implementazioni Haskell non ha bisogno che:

Prelude> :module Random
Prelude Random> randomRIO (1,6 :: Int)
(...) -- GHC prints some stuff here
6
Prelude Random> randomRIO (1,6 :: Int)
1

Quindi, probabilmente ho capito male la monade Stato, perché quello che ho potuto vedere nella maggior parte dei tutorial non sembra essere stato "permanente", ma solo un modo conveniente per infilare stato.

Quindi ... Come posso avere stato che viene inizializzato automaticamente (possibile da alcune funzione che utilizza l'ora e altri dati non molto prevedibile), come il modulo casuale lo fa?

Grazie mille!

È stato utile?

Soluzione

randomRIO utilizza la monade IO. Questo sembra funzionare bene in l'interprete perché l'interprete funziona anche in monade IO. Questo è quello che si sta vedendo nel tuo esempio; non si può effettivamente farlo al massimo livello nel codice -. che avrebbe dovuto metterlo in un fai-da un'espressione come tutte le monadi comunque

In generale, il codice si dovrebbe evitare la monade IO, perché una volta che il codice utilizza la monade IO, è legato a stato esterno per sempre - non si può uscirne (vale a dire se si dispone di codice che utilizza la monade IO , qualsiasi codice che chiama anche deve usare la monade IO, non c'è modo sicuro per "uscire" di esso). Così la monade IO dovrebbe essere utilizzato solo per le cose come accesso l'ambiente esterno, le cose in cui è assolutamente necessario.

Per cose come stato autonomo locale, non si dovrebbe usare la monade IO. È possibile utilizzare la monade State come lei ha detto, oppure è possibile utilizzare la monade ST. La monade ST contiene un sacco di le stesse caratteristiche monade IO; cioè non v'è celle mutabili STRef, analoghe a IORef. E la cosa bella di ST rispetto a IO è che quando si è fatto, è possibile chiamare runST su una monade ST per ottenere il risultato del calcolo fuori della monade, che non si può fare con IO.

Per quanto riguarda "nascondere" lo stato, che appena si presenta come parte della sintassi del fai-da espressioni in Haskell per monadi. Se si pensa che è necessario passare in modo esplicito lo stato, allora non si sta utilizzando correttamente la sintassi monade.

Ecco il codice che utilizza IOREF nel IO Monade:

import Data.IORef
foo :: IO Int -- this is stuck in the IO monad forever
foo = do x <- newIORef 1
         modifyIORef x (+ 2)
         readIORef x
-- foo is an IO computation that returns 3

Ecco il codice che utilizza la monade ST:

import Control.Monad.ST
import Data.STRef
bar :: Int
bar = runST (do x <- newSTRef 1
                modifySTRef x (+ 2)
                readSTRef x)
-- bar == 3

La semplicità del codice è sostanzialmente lo stesso; tranne che in quest'ultimo caso si può ottenere il valore di monade, e nel primo non possiamo senza mettere in una seconda calcolo IO.

Altri suggerimenti

secretStateValue :: IORef SomeType
secretStateValue = unsafePerformIO $ newIORef initialState
{-# NOINLINE secretStateValue #-}

Ora accedere tuo secretStateValue con readIORef e writeIORef , nella monade IO.

  

Quindi, probabilmente ho capito male la monade Stato, perché quello che ho potuto vedere nella maggior parte dei tutorial non sembra essere stato "permanente", ma solo un modo conveniente per infilare stato.

La monade stato è precisamente circa filettatura stato attraverso qualche applicazione.

Se si desidera che lo stato di livello superiore, che è al di fuori della lingua (e si dovrà utilizzare una variabile mutabile globale). Si noti come questo probabilmente complicato filo di sicurezza del codice - come viene inizializzato quello stato? e quando? E per quale thread?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top