Wiem, że w hackage jest co najmniej jedna biblioteka, która ma kilka gotowych transformatorów monad do tego zadania, ale zwykle zwracam się do pakietu rur, aby przetasować swój własny, kiedy go potrzebuję. Używam pipe-4.0.0, który będzie w hackage w ten weekend, ale możesz go wcześniej pobrać z github repo.
użyłem również terminal-progress-bar package so that it makes a nice terminal animation as well.
{-# language BangPatterns #-}
import Pipes
import qualified Pipes.Prelude as P
import Control.Monad.IO.Class
import System.ProgressBar
import System.IO (hSetBuffering, BufferMode(NoBuffering), stdout)
-- | Takes the total size of the stream to be processed as l and the function
-- to map as fn
progress l = loop 0
where
loop n = do
liftIO $ progressBar (msg "Working") percentage 40 n l
!x <- await -- bang pattern to make strict
yield x
loop (n+1)
main = do
-- Force progress bar to print immediately
hSetBuffering stdout NoBuffering
let n = 10^6
let heavy x = last . replicate n $ x -- time wasting function
r <- P.toListM $ each [1..100] >-> P.map heavy >-> progress 100
putStrLn ""
return r
To ożywia:
> Working [=>.......................] 7%
> Working [=====>...................] 20%
Każda zmiana powoduje skasowanie ostatniego pasek tak to tylko trwać jeden wiersz na terminalu. Następnie kończy się tak:
> main
Working [=========================] 100%
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]
Należy zauważyć, że spowoduje to przepełnienie na dużych listach z powodu użycia 'toListM'. Aby przesyłać strumieniowo wyniki w stałej pamięci, możesz użyć pętli 'for', takich jak' runEffect $ for (każdy [1..100]> -> Pmap heavy> -> progress 100) (lift. Print) 'lub ty może używać "P.print' convenience" Consumer ". –
@GabrielGonzalez - Pamiętam, że najlepszym sposobem, aby przesłać potok do leniwej listy, była niestandardowa leniwy monter pisarza, a wbudowana leniwy monter pisarza nie był wystarczająco leniwy. Czy istnieje lepsza metoda przesyłania strumieniowego do leniwych list? – Davorak
'toList' zastępuje starą leniwą sztuczkę pisarza monada, jednak żadne z tych dwóch rozwiązań nie może uczynić nieczystego" Producenta "czystą i leniwą listą. Jednak nie ma takiej potrzeby, ponieważ 'Producent' ** to ** nieczysta lista, którą chcesz, a idiomatycznym zadaniem jest pozostawienie jej jako" producenta ". –