Вы были почти там; вам просто нужно управлять государством.
main = do
bs <- L.unpack `fmap` L.getContents
flip execStateT 0 $ runEffect $ produceList bs >-> buzzHash >-> hoist lift stdoutLn
Я предполагаю, что вы не хотите восстанавливать состояние, поэтому я использую execStateT
, а не runStateT
.
Единственное любопытство здесь в том, что stdoutLn
был помечен как Consumer Word64 IO ()
. Поэтому я использую hoist lift
, чтобы сделать его Consumer Word64 (StateT Word64 IO) ()
Все в серии a >-> b >-> c
должно согласовываться в базовой монаде и возвращаемом типе.
Вот еще несколько комментариев, которые могут сэкономить вам время. Первый produceFromList
это each
.
Более того, вы могли бы избежать hoist lift
, переименовав свой stdoutLn
:
stdoutLn :: MonadIO m => Consumer Word64 m ()
stdoutLn = do
a <- await
liftIO $ print a
Но вот беда: вы не повторяете действие. Это должен быть цикл:
stdoutLn :: MonadIO m => Consumer Word64 m ()
stdoutLn = do
a <- await
liftIO $ print a
stdoutLn
на самом деле это уже доступно как P.print
, поэтому мы можем написать
import qualified Pipes.Prelude as P
main = do
bs <- L.unpack `fmap` L.getContents
flip execStateT 0 $ runEffect $ each bs >-> buzzHash >-> P.print
Насколько я вас понимаю, buzzHash
тоже должно повторяться бесконечно:
buzzHash = do
x <- await
h <- lift $ get -- pull out previous value
let h' = rotate h 1 `xor` (hashArrW8!x) -- calculate new value
lift $ put h' -- save new value
yield h'
buzzHash
(это forever buzzHash
, где мы используем ваше buzzHash
)
Наконец, если вы
import qualified Pipes.ByteString as PB
import Control.Lens (view) -- (or Lens.Micro.MTL or Lens.Simple)
мы видим, что нам не нужен ленивый ввод-вывод строки байтов, который в любом случае не работает должным образом. Pipes.ByteString
уже имеет нужный нам unpack
, упакованный как линза, так что мы используем view PB.unpack
там, где в других местах мы использовали бы B.unpack
. Итак, в конце мы можем написать
main = flip evalStateT 0 $ runEffect $ view PB.unpack PB.stdin >-> buzzHash >-> P.print
Когда он находится в этой форме, мы видим, что не используем базовое состояние конвейера, кроме как в buzzHash
, поэтому мы можем локализовать это.
import Pipes.Lift (evalStateP)
main = runEffect $ view PB.unpack PB.stdin >-> evalStateP 0 buzzHash >-> P.print
или, если хотите, можете переписать
buzzHash' :: Monad m => Word64 -> Pipe Word8 Word64 m r
buzzHash' n = evalStateP n $ forever $ do
x <- await
h <- lift $ get -- pull out previous value
let h' = rotate h 1 `xor` (hashArrW8!x) -- calculate new value
lift $ put h' -- save new value
yield h'
Тогда вы бы написали
main = runEffect $ view PB.unpack PB.stdin >-> buzzHash' 0 >-> P.print
person
Michael
schedule
22.02.2016