2014-07-03 16 views
9

Tôi có lẽ chỉ dành một ngày của thời gian tính toán một cách vô ích :)Có cách nào để 'đọc' lười biếng không?

Vấn đề là I (ngây thơ) viết về 3.5GB của (nén) [(Text, HashMap Text Int)] dữ liệu vào một tập tin và tại thời điểm đó chương trình của tôi bị rơi. Tất nhiên không có ] cuối cùng ở cuối dữ liệu và kích thước tuyệt đối của nó làm cho việc chỉnh sửa nó bằng tay không thể.

Dữ liệu được định dạng qua Prelude.show và ngay tại thời điểm này tôi nhận thấy rằng Prelude.read sẽ cần toàn bộ tập dữ liệu vào bộ nhớ (không thể) trước khi dữ liệu được trả về.

Bây giờ ... có cách nào để khôi phục dữ liệu mà không cần phải viết một trình phân tích cú pháp theo cách thủ công không?

Cập nhật 1

main = do 
    s <- getContents 
    let hs = read s :: [(String, M.Map String Integer)] 
    print $ head hs 

này tôi đã cố gắng ... nhưng nó chỉ giữ tốn nhiều bộ nhớ hơn cho đến khi nó bị giết bởi hệ điều hành.

+0

@ n.m. thậm chí sau đó 'read' sẽ cố gắng đọc mọi thứ vào bộ nhớ trước khi trả về một phần tử duy nhất trong danh sách. – fho

+0

Xin lỗi tôi đã hiểu lầm, ý bạn là hàm Haskell 'read', không đọc từ tập tin. –

Trả lời

7

Câu trả lời Daniels có thể được mở rộng để phân tích cú pháp toàn bộ danh sách cùng một lúc bằng cách sử dụng chức năng này. Sau đó, bạn có thể truy cập trực tiếp vào danh sách theo cách bạn muốn

lazyread :: Read a => [Char] -> [a] 
lazyread xs = go (tail xs) 
    where go xs = a : go (tail b) 
     where (a,b) = head $ reads xs 
+0

Tuyệt vời! Bạn vừa lưu lại ngày của tôi :) – fho

1

Xóa thủ công phần mở '['. Sau đó bạn có thể sử dụng reads (lưu ý s) để truy cập getContents từng bước.

9

Sắp xếp. Bạn vẫn sẽ viết một trình phân tích cú pháp theo cách thủ công ... nhưng nó là một trình phân tích cú pháp rất ngắn và rất dễ viết, bởi vì hầu như tất cả nó sẽ được gửi đến read. Ý tưởng là: read là nghiêm ngặt, nhưng reads, khi làm việc trên một yếu tố duy nhất, là lười biếng. Vì vậy, chúng tôi chỉ cần loại bỏ các bit mà reads không mong đợi khi làm việc trên một phần tử duy nhất. Dưới đây là một ví dụ để giúp bạn bắt đầu:

> let s = "[3,4,5," ++ undefined 
> reads (drop 1 s) :: [(Int, String)] 
[(3,",4,5,*** Exception: Prelude.undefined 

tôi bao gồm các undefined vào cuối như bằng chứng cho thấy nó là trong thực tế không đọc toàn bộ String trước khi sản xuất các phân tích cú pháp 3 ở phần đầu của danh sách.

Các vấn đề liên quan