2013-08-06 23 views
5

Khi xử lý từng phần tử trong một seq Tôi thường sử dụng firstrest. Tuy nhiên, điều này sẽ gây ra một số lazy-seq để mất "sự lười biếng" của nó bằng cách gọi số seq trên đối số. Giải pháp của tôi đã được sử dụng (first (take 1 coll))(drop 1 coll) tại vị trí của họ khi làm việc với lazy-seq s và trong khi tôi nghĩ rằng drop 1 là tốt, tôi không đặc biệt thích phải gọi firsttake để lấy phần tử đầu tiên.Cách thành ngữ để lấy yếu tố đầu tiên của một seq lười biếng trong clojure

Có cách nào thành ngữ hơn để thực hiện việc này không?

Trả lời

10

Các docstrings cho firstrest nói rằng các chức năng gọi seq trên lập luận của mình để truyền đạt ý tưởng rằng bạn không cần phải gọi seq mình khi đi qua trong một bộ sưu tập seqable mà không phải là của riêng mình một seq, như, nói , một véc tơ hoặc bộ. Ví dụ:

(first [1 2 3]) 
;= 1 

sẽ không hoạt động nếu first không gọi seq về đối số của nó; bạn cần phải nói số

(first (seq [1 2 3])) 

thay vào đó, điều này sẽ bất tiện.

Cả hai takedrop cũng gọi seq trên đối số của chúng, nếu không bạn không thể gọi chúng trên vectơ và tương tự như đã giải thích ở trên. Trên thực tế, điều này đúng với tất cả các bộ sưu tập seq tiêu chuẩn - những bộ phận không gọi trực tiếp là seq được xây dựng dựa trên các thành phần cấp thấp hơn.

Không có cách nào điều này làm giảm sự lười biếng của các địa chỉ lười biếng. Việc bắt buộc/thực hiện xảy ra là kết quả của cuộc gọi first/rest là số tiền nhỏ nhất có thể để có được kết quả được yêu cầu. (Điều đó phụ thuộc vào loại đối số như thế nào, nếu nó không thực sự là lười biếng, không có sự thực hiện thêm nào liên quan đến cuộc gọi first; nếu nó là một phần lười biếng - đó là, chunked - sẽ có thêm một số thực hiện (lên đến 32 yếu tố ban đầu sẽ được tính cùng một lúc), nếu nó hoàn toàn lười biếng, chỉ có các yếu tố đầu tiên sẽ được tính toán.)

Rõ ràng , khi thông qua một seq lười, phải buộc thực hiện yếu tố đầu tiên của nó - - đó là toàn bộ vấn đề. rest thực sự là hơi lười ở chỗ nó thực sự không bắt buộc thực hiện phần "phần còn lại" của seq (đó là trái ngược với next, về cơ bản tương đương với (seq (rest ...))). Thực tế là nó buộc yếu tố đầu tiên được nhận ra để nó có thể bỏ qua nó ngay lập tức là một sự lựa chọn thiết kế có ý thức mà tránh lớp không cần thiết của các đối tượng seq lười biếng và giữ đầu của seq gốc; bạn có thể nói điều gì đó như (lazy-seq (rest xs)) để trì hoãn ngay cả việc thực hiện ban đầu này, với chi phí giữ cho đến xs cho đến khi nhận ra trình bao bọc seq lười biếng được nhận ra.

+0

Cảm ơn vì điều đó. Tôi nghĩ đó là sự khác biệt giữa chunked và lười biếng hoàn toàn đã ném tôi đi. Đặc biệt khi tôi lần đầu tiên làm việc với lazy-seq tôi nghĩ rằng bất cứ điều gì tôi đã làm việc trên phải đã gây ra vấn đề khi chunked vì vậy tôi chỉ bị mắc kẹt với nó sau đó. – robertjlooby

+0

Có, chunking có thể dẫn đến kết quả bất ngờ nếu một người quên nó. 'take' sử dụng cả' first' và 'rest' trong quá trình thực hiện, trong khi' drop' được xây dựng trên 'rest', vì vậy chúng không giúp ích gì.Unchunking là có thể, nhưng chỉ theo nghĩa là người ta có thể gây ra các phép biến đổi được xếp chồng lên nhau trên các phần tử bị chẻ được đánh giá một phần tử tại một thời điểm; các seq chunked cơ bản sẽ luôn luôn nhận ra khối của nó đầy đủ. (Cách để làm điều đó là để quấn các seq chunked trong một seq unchunking, có lẽ sản xuất với '(reify clojure.lang.ISeq ...)' với seq ban đầu trong một đóng cửa.) –

+0

Bạn có chắc 'take'/'drop' cũng thực sự gọi là' seq'? Chỉ cần thử nó trong repl và gọi 'class' với' (range) ',' (take 1 (range)) ',' (drop 1 (range)) 'tất cả cho' clojure.lang.LazySeq'. Gọi với '(phần còn lại (khoảng))', '(seq (dải))' cho 'clojure.lang.ChunkedCons'. – robertjlooby

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