Tôi có biến đơn nguyên tiếp theo:đầu ra Lazy từ hành động monadic
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
Về cơ bản, nó sử dụng cơ bản Iteratee
mà đọc và xử lý tài liệu pdf (yêu cầu nguồn truy cập ngẫu nhiên, do đó nó sẽ không giữ cho tài liệu bộ nhớ mọi lúc).
Tôi cần triển khai một chức năng sẽ lưu tài liệu pdf và tôi muốn nó trở nên lười biếng, bạn có thể lưu tài liệu vào bộ nhớ không đổi.
tôi có thể sản xuất lười biếng ByteString
:
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BS
save :: Monad m => Pdf m ByteString
save = do
-- actually it is a loop
str1 <- serializeTheFirstObject
storeOffsetForTheFirstObject (BS.length str1)
str2 <- serializeTheSecondObject
storeOffsetForTheSecondObject (BS.length str2)
...
strn <- serializeTheNthObject
storeOffsetForTheNthObject (BS.length strn)
table <- dumpRefTable
return mconcat [str1, str2, ..., strn] `mappend` table
Nhưng thực tế sản lượng có thể phụ thuộc vào sản lượng trước đó. (Chi tiết: tài liệu pdf có chứa cái gọi là "bảng tham chiếu" với độ lệch tuyệt đối theo byte của mỗi đối tượng bên trong tài liệu. Nó chắc chắn phụ thuộc vào độ dài của ByteString
đối tượng pdf được tuần tự hóa.)
Làm thế nào để đảm bảo rằng chức năng save
sẽ không buộc toàn bộ ByteString
trước khi trả lại cho người gọi?
Có tốt hơn khi gọi lại làm đối số và gọi nó mỗi lần tôi có thứ gì đó để xuất?
import Data.ByteString (ByteString)
save :: Monad m => (ByteString -> Pdf m()) -> Pdf m()
Có giải pháp nào tốt hơn không?
Tôi vừa thêm "triển khai" cho chức năng 'lưu' để giải quyết vấn đề. Có, nó phải là thuật toán 1-pass, nhưng nó không phải là một vấn đề. Bản thân vấn đề: khi tôi gọi 'mconcat' để tạo ra' ByteString' cuối cùng, tôi đã có nó trong bộ nhớ. Giả sử tập tin pdf rất lớn, tôi không có đủ bộ nhớ cho nó. Tôi chỉ muốn lưu trữ bù trừ, không phải chính bản thân 'ByteString'. Có vẻ như cách tiếp cận gọi lại giải quyết vấn đề, nhưng tôi nghĩ giải pháp tốt hơn nên tồn tại. – Yuras
Lạ lùng, nhưng tôi không nhận được thông báo về chỉnh sửa của bạn vào ngày 6 tháng 6. 'Bulder' chắc chắn nhanh hơn' ByteString' khi bạn muốn 'mappend', nhưng vấn đề là sử dụng bộ nhớ, không phải hiệu năng. 'str1',' str2', vv sẽ có trong bộ nhớ (bắt buộc bởi BS.length) trước 'mconcat'. – Yuras