2012-06-22 23 views
15

Một thời gian trước, tôi chạy qua an article on FingerTrees (Xem thêm an accompanying Stack Overflow Question) và gửi ý tưởng đi. Cuối cùng tôi đã tìm thấy một lý do để sử dụng chúng.Tại sao FingerTrees không sử dụng đủ để thực hiện ổn định?

Vấn đề của tôi là Data.FingerTree package dường như có một chút thối quanh các cạnh. Hơn nữa, Data.Sequence trong gói Container sử dụng cấu trúc dữ liệu re-implements một phiên bản (có thể tốt hơn), nhưng không xuất nó.

Về mặt lý thuyết hữu ích vì cấu trúc này có vẻ như, nó dường như không nhận được rất nhiều sử dụng thực tế hoặc sự chú ý. Mọi người thấy rằng FingerTrees không hữu ích như một vấn đề thực tế, hay đây là một trường hợp không đủ chú ý?


giải thích thêm:

Tôi quan tâm đến việc xây dựng một văn bản tổ chức cấu trúc dữ liệu có tính chất nối tốt. Hãy suy nghĩ về việc xây dựng một tài liệu HTML từ các phân đoạn khác nhau. Hầu hết các giải pháp dựng sẵn đều sử dụng bytestrings, nhưng tôi thực sự muốn một cái gì đó liên quan đến văn bản Unicode đúng cách. Kế hoạch của tôi vào lúc này là lớp các đoạn Data.Text thành một FingerTree.

Tôi cũng muốn mượn mẹo từ Data.Vector lấy lát mà không cần sao chép bằng thao tác (bù đắp, độ dài). Data.Text.Text có được xây dựng trong kiểu dữ liệu, nhưng chỉ sử dụng nó cho uncons hiệu quả và unnoc opperations. Trong FingerTree, thông tin này có thể dễ dàng trở thành v hoặc chú thích của cây.

+3

Tại sao không sử dụng Data.Text.Lazy.Text? – dave4420

+1

Hầu hết mọi người không cần phải giao tiếp với cấu trúc cây ngón tay; họ chỉ cần những gì họ nhận được từ 'Data.Sequence'. Rất ít người thực sự gặp phải một trường hợp mà họ cần phải sử dụng cấu trúc dữ liệu trực tiếp. –

Trả lời

17

Để trả lời câu hỏi của bạn về cây ngón tay nói riêng, tôi nghĩ vấn đề là chúng có chi phí cố định tương đối cao so với mảng và phức tạp hơn các cách khác để đạt được kết nối hiệu quả. Một Builder có một giao diện hiệu quả hơn cho việc thêm các khối, và chúng thường có sẵn (xem các liên kết trong câu trả lời của @ informatikr). Giả sử rằng Data.Text.Lazy được triển khai với danh sách các khối được liên kết và bạn đang tạo một Data.Text.Lazy từ trình tạo. Trừ khi bạn có rất nhiều khối (có thể hơn 50), hoặc đang truy cập dữ liệu gần cuối danh sách nhiều lần, chi phí cố định cao của cây ngón tay có thể không đáng giá.

Triển khai Data.Sequence chuyên về lý do hiệu suất và không phải là chung chung như giao diện đầy đủ được cung cấp bởi gói fingertree. Đó là lý do tại sao nó không được xuất khẩu; nó không thực sự có thể sử dụng nó cho bất cứ điều gì khác hơn là một Sequence.

Tôi cũng nghi ngờ rằng nhiều lập trình viên đang thua lỗ về cách thực sự sử dụng chú giải một mặt, vì nó nằm phía sau một rào cản trừu tượng khá lớn. Vì vậy, nhiều người sẽ không sử dụng nó bởi vì họ không thấy nó có thể hữu ích như thế nào so với các loại dữ liệu khác.

Tôi đã không thực sự nhận được nó cho đến khi tôi đọc loạt blog của Chung-chieh Shan trên word numbers (part2, part3, part4). Đó là bằng chứng cho thấy ý tưởng này chắc chắn có thể được sử dụng trong mã thực tế.

Trong trường hợp của bạn, nếu bạn cần cả hai kiểm tra một phần kết quả và có hiệu quả gắn thêm, sử dụng một ngón tay có thể tốt hơn so với một người xây dựng. Tùy thuộc vào việc thực hiện của nhà xây dựng, bạn có thể sẽ thực hiện nhiều công việc lặp đi lặp lại khi bạn chuyển đổi thành Text, thêm nội dung khác vào trình tạo, chuyển đổi thành Text một lần nữa, v.v.

Bạn có thể quan tâm đến gói splaytree của tôi, cung cấp các cây splay có chú thích hình một và một số cấu trúc khác nhau được xây dựng dựa trên chúng. Khác với chính cây splay, các mô-đun SetRangeSet có API hoàn chỉnh hơn hoặc ít hơn, mô-đun Sequence chủ yếu là bộ xương mà tôi đã sử dụng để thử nghiệm. Nó không phải là một giải pháp "bao gồm pin" cho những gì bạn đang tìm kiếm (một lần nữa, câu trả lời của @ informatikr cung cấp những câu trả lời đó), nhưng nếu bạn muốn thử nghiệm các chú thích đơn hình, nó có thể hữu ích hơn Data.FingerTree. Hãy nhận biết rằng một cây splay có thể bị mất cân bằng nếu bạn đi qua tất cả các phần tử theo thứ tự (hoặc liên tục snoc vào cuối, hoặc tương tự), nhưng nếu nối và tra cứu là hiệu suất xen kẽ có thể là tuyệt vời.

+0

John - gói splaytree của bạn trông rất thú vị. Bạn sẽ có thể ghi lại sự phức tạp tiệm cận của các chức năng - nhìn vào nó ngay bây giờ, tôi không có ý tưởng làm thế nào tiệm cận của nó so sánh với ngón tay. – reinerp

+0

@reinerp: có một chút khó khăn để làm như vậy cho các cây chơi, nhưng bạn nói đúng tôi nên làm. Bất kỳ hoạt động đơn lẻ nào của 'tra cứu',' chèn', 'xóa', sẽ có một giá trị phân bổ theo thời gian O (log n), với trường hợp xấu nhất là O (n). Tuy nhiên, độ phức tạp mong đợi cho một chuỗi các hoạt động có thể tốt hơn, xem Sleator & Tarjan của giấy "tự điều chỉnh nhị phân tìm kiếm cây" cho một cuộc thảo luận về điều đó. –

+0

Tuyệt vời, cảm ơn. Thú vị giấy! – reinerp

7

Bỏ qua câu hỏi Cây ngón tay của bạn và chỉ trả lời giải thích thêm của bạn: bạn đã xem xét Data.Text.Lazy.Builder hoặc, đặc biệt để xây dựng HTML, blaze-html?

Cả hai đều cho phép ghép nối nhanh. Để cắt, nếu đó là quan trọng để giải quyết vấn đề của bạn, họ có thể không có hiệu suất lý tưởng.

+1

Vì vậy, hãy để tôi hỏi một theo dõi: Data.Text.Lazy.Builder hiệu suất trông giống như nó được dựa trên một foldr crafted cũng/xây dựng quy tắc viết lại (xem dòng ~ 290). Dự án của tôi liên quan đến việc tạo ra một DLS scripting mà churns ra văn bản từ các mẫu (không cần thiết HTML mặc dù đó là một trường hợp sử dụng chính). Tôi tin rằng ý nghĩa sự lựa chọn của những gì để ghép/lát và khi xảy ra lúc chạy mà tối ưu hóa thời gian biên dịch là không hiệu quả trong trường hợp này. Bạn có đồng ý không? –

+2

Không, điều đó không đúng.Quy tắc viết lại mà bạn đang xem chỉ ở đó để loại bỏ một số kiểm tra giới hạn mảng, và không ảnh hưởng đến hiệu suất tiệm cận. Các nhà xây dựng sử dụng một kỹ thuật rất giống với các danh sách khác biệt (http://en.wikipedia.org/wiki/Difference_list) để đảm bảo kết nối O (1), mà không yêu cầu bất kỳ việc tối ưu hóa biên dịch nào để áp dụng. – reinerp

10

Ngoài câu trả lời của John Lato, tôi sẽ thêm một số chi tiết cụ thể về hiệu suất của cây ngón tay, vì tôi đã dành chút thời gian xem xét điều đó trong quá khứ.

Bản tóm tắt rộng là:

  • Data.Sequence có yếu tố liên tục lớn và asymptotics: nó gần như là nhanh như [] khi truy cập vào mặt trước của danh sách (nơi cả hai cấu trúc dữ liệu có O (1) asymptotics) , và nhanh hơn nhiều ở những nơi khác trong danh sách (trong đó Data.Sequence 's asymptotics lôgarít trounce []' s tuyến tính tiệm cận).

  • Data.FingerTree có cùng tiệm cận như Data.Sequence, nhưng có độ trễ chậm hơn.

Cũng giống như danh sách, cây ngón tay có các chi phí bộ nhớ cho mỗi yếu tố cao, vì vậy họ cần được kết hợp với chunking cho bộ nhớ tốt hơn và sử dụng bộ nhớ cache. Thật vậy, một vài gói thực hiện việc này (yi, trifecta, rope). Nếu Data.FingerTree có thể được mang đến gần Data.Sequence về hiệu suất, tôi hy vọng sẽ thấy loại Data.Text.Sequence, đã triển khai cây ngón tay gồm các giá trị Data.Text. Loại như vậy sẽ mất hoạt động truyền trực tuyến của Data.Text.Lazy, nhưng được hưởng lợi từ việc truy cập ngẫu nhiên được cải thiện và hiệu suất nối. (Tương tự như vậy, tôi sẽ muốn nhìn thấy Data.ByteString.SequenceData.Vector.Sequence.)

Trở ngại để thực hiện những bây giờ là không có hiệu quả generic thực hiện cây ngón tay tồn tại (xem bên dưới nơi tôi thảo luận thêm về điều này). Để thực hiện hiệu quả việc thực hiện Data.Text.Sequence, người ta phải hoàn toàn thực hiện lại các cây ngón tay, đặc biệt là Text - giống như Data.Text.Lazy hoàn thành các danh sách hoàn chỉnh, chuyên về Text. Thật không may, cây ngón tay phức tạp hơn nhiều so với danh sách (đặc biệt là concatenation!), Vì vậy đây là một số lượng đáng kể công việc.

Vì vậy, như tôi nhìn thấy nó câu trả lời là:

  • cây ngón tay chuyên là rất lớn, nhưng rất nhiều công việc để thực hiện
  • chunked cây ngón tay (ví dụ Data.Text.Sequence) sẽ tuyệt vời, nhưng tại trình bày hiệu suất kém của Data.FingerTree có nghĩa là chúng không phải là giải pháp thay thế khả thi đối với các danh sách chunked trong trường hợp phổ biến là
  • nhà xây dựng và danh sách chunked đạt được nhiều lợi ích của cây ngón tay chunked, và vì vậy chúng đủ cho trường hợp phổ biến
  • trong trường hợp không phổ biến trường hợp người xây dựng và danh sách chunked không đủ, chúng tôi nghiến răng và đưa ra các yếu tố liên tục kém của cây ngón chunked (ví dụ: trong yi và trifecta).

trở ngại đối với một cây ngón tay hiệu quả và generic

Phần lớn sự chênh lệch hiệu suất giữa Data.SequenceData.FingerTree là do hai optimisations trong Data.Sequence:

  • Các loại biện pháp chuyên để Int, để đo lường thao tác sẽ biên dịch xuống số học số nguyên hiệu quả thay vì

  • The measure type is unpacked into the Deep constructor, lưu các tham số con trỏ vào vòng trong của các hoạt động của cây.

Có thể áp dụng những optimisations trong trường hợp tổng quát của Data.FingerTree bằng cách sử dụng data families for generic unpacking và bằng cách khai thác inliner và specialiser GHC của - xem fingertree-unboxed package của tôi, mang lại hiệu suất cây ngón tay chung gần như lên đến đó của Data.Sequence. Thật không may, những kỹ thuật này có một số vấn đề quan trọng:

  • data families for generic unpacking is unpleasant for the user, bởi vì họ phải xác định rất nhiều trường hợp. Không có giải pháp rõ ràng cho vấn đề này.

  • cây ngón tay sử dụng đệ quy đa hình, mà chuyên gia của GHC không xử lý tốt (1, 2). Điều này có nghĩa là, để có đủ chuyên môn về loại đo lường, chúng tôi cần rất nhiều các pragmas INLINE, điều này khiến GHC tạo ra một lượng lớn mã.

Do những vấn đề này, tôi chưa bao giờ phát hành gói trên Hackage.

+0

Tôi biết điều này là gần sáu năm sau đó, nhưng trong GHC 8.2, Edward Yang thực hiện ba lô, trong đó, gần như nói, cung cấp một cách để chuyên toàn bộ mô-đun, bao gồm giải nén dữ liệu đa hình. Chưa có ai viết vân tay như một mô-đun ba lô không xác định, nhưng điều này sẽ giải quyết các vấn đề được trích dẫn trong câu trả lời này. –

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