Sono alle prese con il problema generale su come effettuare un calcolo statico in Haskell generare risultati pigramente. Per esempio. il seguente semplice algoritmo può essere espresso con l'aiuto della funzione di generatore di Python come un calcolo statico ma "pigro", eseguendo solo i passi necessari per raggiungere la successiva dichiarazione yield
e quindi restituire il flusso di controllo al chiamante fino a quando viene richiesto l'elemento successivo :Come far sì che il calcolo ST produca flusso di risultati lazy (o funzioni come un co-routine)?
def solveLP(vmax0, elems):
elem_true_ixs = [ [ ei for ei, b in enumerate(row) if b ] for row in elems ]
return go(vmax0, elem_true_ixs)
def go(vmax, mms):
if not mms:
yield []
else:
for ei in mms[0]:
maxcnt = vmax[ei]
if not maxcnt > 0:
continue
vmax[ei] = maxcnt-1 # modify vmax vector in-place
for es in go(vmax, mms[1:]):
# note: inefficient vector-concat operation
# but not relevant for this question
yield [ei]+es
vmax[ei] = maxcnt # restore original vmax state
for sol in solveLP([1,2,3],[[True,True,False],[True,False,True]]):
print sol
# prints [0,2], [1,0], and [1,2]
Questo può essere facilmente tradotto in un pigro computazione Haskell (ad esempio quando m
è specializzato per Logic
o []
), ad esempio
import Control.Monad
import qualified Data.Vector.Unboxed as VU
solveLP :: MonadPlus m => VU.Vector Int -> [[Bool]] -> m [Int]
solveLP vmax0 elems = go vmax0 elemTrueIxs
where
-- could be fed to 'sequence'
elemTrueIxs = [ [ ei | (ei,True) <- zip [0::Int ..] row ] | row <- elems ]
go vmax [] = return []
go vmax (m:ms) = do
ei <- mlist m
let vmax' = vmax VU.// [(ei, maxcnt-1)] -- this operation is expensive
maxcnt = vmax VU.! ei
guard $ maxcnt > 0
es <- go vmax' ms
return $ (ei:es)
mlist = msum . map return
... ma mi piacerebbe essere in grado di avvicinarsi alla realizzazione di Python originale, utilizzando vettori mutevoli, e la modifica di un singolo vettore vmax0
sul posto (come ho solo bisogno di aumentare/diminuire un singolo elemento, e copiare l'intero vettore solo per sostituire un singolo elemento è piuttosto un overhead più lungo diventa il vettore); per favore nota che questo è solo un esempio di giocattolo per una classe di algoritmi che ho cercato di implementare
Quindi la mia domanda è - supponendo che ci sia un modo per farlo - come posso esprimere un algoritmo così statico in la monade ST mentre è ancora in grado di restituire i risultati al chiamante non appena vengono prodotti durante il calcolo? Ho provato a combinare la monade ST con una lista monad tramite trasformatori monad ma non riuscivo a capire come farlo funzionare ...
Lo stato condiviso in questo caso non può essere memorizzato in un 'STRef', quindi la risposta non è così semplice. – dflemstr
@dflemstr Lo stato condiviso * può *, tuttavia, essere memorizzato in un 'STArray', quindi la risposta è davvero semplice come questa. –
@DanielWagner, sì, usando 'STArray's, è possibile; tuttavia, non vedo questa risposta che si occupa delle stranezze nell'usare 'STArray's :) – dflemstr