Thậm chí nhiều hơn pipes-parse
bạn rất có thể muốn xem pipes-group
. Đặc biệt, chúng ta hãy xem xét các chức năng
-- this type is slightly specialized
chunksOf
:: Monad m =>
Int ->
Lens' (Producer a m x) (FreeT (Producer a m) m x)
Bit Lens'
có lẽ là đáng sợ nhưng có thể được loại bỏ một cách nhanh chóng: nó khẳng định rằng chúng tôi có thể chuyển đổi Producer a m x
-FreeT (Producer a m) m x
[0]
import Control.Lens (view)
chunkIt :: Monad m => Int -> Producer a m x -> FreeT (Producer a m) m x
chunkIt n = view (chunksOf n)
Vì vậy, bây giờ chúng ta phải tìm ra những gì cần làm với bit FreeT
. Đặc biệt, chúng ta sẽ muốn thâm nhập vào các gói free
và rút khỏi chức năng iterT
iterT
:: (Functor f, Monad m) =>
(f (m a) -> m a) ->
(FreeT f m a -> m a)
Chức năng này, iterT
, hãy cho chúng tôi "tiêu thụ" một "bước" FreeT
tại một thời điểm. Để hiểu điều này, đầu tiên chúng tôi sẽ chuyên các loại iterT
để thay thế f
với Producer a m
runChunk :: Monad m =>
(Producer a m (m x) -> m x) ->
(FreeT (Producer a m) m x -> m x)
runChunk = iterT
Đặc biệt, runChunk
có thể "chạy" một FreeT
đầy Producer
s chừng nào chúng ta nói với nó như thế nào để chuyển đổi một Producer a m (m x)
vào một số m
-action. Điều này có thể bắt đầu trông quen thuộc hơn. Khi chúng ta xác định đối số đầu tiên của runChunk
, chúng ta chỉ cần thực hiện một Producer
, trong trường hợp này, sẽ không có nhiều hơn số lượng phần tử đã chọn.
Nhưng điều gì xảy ra với giá trị trả lại hiệu quả m x
? Đó là "sự tiếp tục", ví dụ: tất cả các khối đến sau sau hiện tại bạn đang viết. Vì vậy, ví dụ, chúng ta hãy giả sử chúng ta đã có một Producer
của Char
s và chúng tôi muốn in và linebreak sau 3 ký tự
main :: IO()
main = flip runChunk (chunkIt 3 input) $ \p -> _
Các _
lỗ vào thời điểm này có kiểu IO()
với p
trong bối cảnh tại nhập p :: Producer Char IO (IO())
. Chúng ta có thể tiêu thụ đường ống này với for
, thu thập kiểu trả về của nó (đó là sự tiếp tục, một lần nữa), phát ra một dòng mới, và sau đó chạy tiếp tục.
input :: Monad m => Producer Char m()
input = each "abcdefghijklmnopqrstuvwxyz"
main :: IO()
main = flip runChunk (chunkIt 3 input) $ \p -> do
cont <- runEffect $ for p (lift . putChar)
putChar '\n'
cont
Và đây cư xử chính xác như mong muốn
λ> main
abc
def
ghi
jkl
mno
pqr
stu
vwx
yz
Để được rõ ràng, trong khi tôi đã làm một chút của triển lãm, đây là mã khá đơn giản khi bạn xem làm thế nào tất cả các mảnh phù hợp với nhau. Đây là toàn bộ danh sách:
input :: Monad m => Producer Char m()
input = each "abcdefghijklmnopqrstuvwxyz"
main :: IO()
main = flip iterT (input ^. chunksOf 3) $ \p -> do
cont <- runEffect $ for p $ \c -> do
lift (putChar c)
putChar '\n'
cont
[0] Ngoài ra còn hơn một chút, nhưng hiện tại vẫn đủ.