2012-06-21 16 views
6

Để bắt đầu, tôi đang sử dụng Windows 7 (64 bit), chạy Java phiên bản 6 (cập nhật 33) bằng cách sử dụng clooj làm IDE của tôi. Tôi đã không cố gắng tái tạo vấn đề của mình trong bất kỳ hệ thống nào khác. Tôi có kinh nghiệm với Clojure, nhưng hoàn toàn không có Java.Macro clojure sẽ bảo tồn thứ tự bản đồ liên kết

Toàn bộ vấn đề tôi đang cố gắng giải quyết là dài để mô tả, nhưng nó tóm lại điều này: giả sử tôi muốn tạo macro có một đối số, một bản đồ liên kết và trả về một vectơ các yếu tố của bản đồ với thứ tự được bảo tồn.

=>(defmacro vectorize-a-map 
    [associative-map] 
    (vec associative-map)) 
=>#'ns/vectorize-a-map 
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8} 
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8]] 

đó làm việc, nhưng thêm một yếu tố khác vào bản đồ và trình tự messes lên ...

=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9} 
=>[[:a 1] [:c 3] [:b 2] [:f 6] [:g 7] [:d 4] [:e 5] [:i 9] [:h 8]] 

Tôi tin rằng tôi đã khám phá ra lý do tại sao điều này xảy ra. Có vẻ như bất cứ điều gì với 8 hoặc ít hơn các yếu tố được khởi tạo như là một PersistentArrayMap, đó là chính xác những gì tôi muốn, bởi vì từ những gì tôi có thể nói, lớp này giữ lại trật tự. Tuy nhiên, bất kỳ thứ gì có 9 hoặc nhiều phần tử được khởi tạo dưới dạng PersistentHashMap, không giữ lại thứ tự.

=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8} 
=>clojure.lang.PersistentArrayMap 
=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9} 
=>clojure.lang.PersistentHashMap 

Tôi muốn macro của mình có thể chụp bản đồ liên kết với mọi kích thước, vì vậy đây là vấn đề. Tôi đã thử loại gợi ý, ràng buộc phá hủy, cho khả năng đọc danh sách và nối kết không cần thiết, tất cả đều không thành công. Để vẽ nó ra, không ai trong số những điều sau đây sẽ làm việc:

(defmacro vectorize-a-map 
    [^clojure.lang.PersistentArrayMap associative-map] 
    (vec associative-map)) 

(defmacro vectorize-a-map 
    [[& associative-map]] 
    (vec associative-map)) 

(defmacro vectorize-a-map 
    [associative-map] 
    (vec 
    (for [x associative-map] 
     x))) 

(defmacro vectorize-a-map 
    [associative-map] 
    `(vector [email protected])) 

Với vấn đề đồ chơi này tôi trình bày, tôi nhận ra tôi chỉ đơn giản là có thể viết vĩ mô của tôi như vậy, và tránh những vấn đề hoàn toàn:

=>(defmacro vectorize-kvs 
    [& elements] 
    (vec (map vec (partition 2 elements)))) 
=>#'ns/vectorize-kvs 
=>(vectorize-kvs :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9) 
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8] [:i 9]] 

Tuy nhiên, đối với vấn đề thực tế Tôi đang cố gắng giải quyết (mà tôi đã không nhận được vào), điều quan trọng (mặc dù không phải 100% cần thiết) mà macro có thể có bản đồ liên kết. Có vẻ như tôi đang tìm cách đưa đối số vào PersistentArrayMap trước khi bất cứ điều gì có cơ hội xảy ra với nó. Có thể có một số cách khác để một giải pháp mà tôi chỉ đơn giản là không xem xét hoặc nhận thức được.

Tôi đã nghiên cứu tốt nhất mà tôi đã biết cách thức và chưa tìm thấy bất kỳ điều gì hữu ích. Có ai có suy nghĩ/lời khuyên nào không?

+0

quy tắc đầu tiên của câu lạc bộ macro là "không viết macro" ... (bạn có thể đoán thứ hai) –

+1

Tôi tưởng tượng quy tắc thứ hai là: "Shut up. Nghiêm túc, đừng viết macro." –

Trả lời

5

bạn có thể làm cho bản đồ của bạn với mảng đồ

user> (map vec (array-map 1 2 3 4 5 6)) 
([1 2] [3 4] [5 6]) 

hoặc với một bản đồ lớn hơn

user> (map vec (apply array-map (range 50))) 
([0 1] [2 3] [4 5] [6 7] [8 9] [10 11] [12 13] [14 15] [16 17] [18 19] [20 21] [22 23] [24 25] [26 27] [28 29] [30 31] [32 33] [34 35] [36 37] [38 39] [40 41] [42 43] [44 45] [46 47] [48 49]) 

như một phần thưởng bạn có thể tránh sử dụng một macro, đó là hữu ích vì macro là không đầu tiên -class và không soạn tốt *


ghi chú trong nhận xét đầu tiên của bạn từ tài liệu trên array map

 Note that an array map will only maintain sort order when un-'modified'. 
Subsequent assoc-ing will eventually cause it to 'become' a hash-map.

Nếu bạn thấy mình tùy thuộc vào thứ tự các khóa trong bản đồ bạn có thể muốn xem xét nếu sorted-map sẽ giúp bạn những gì bạn cần. Nó sẽ mở rộng hơn array-map.Trong ví dụ trên đầu ra là như nhau:

(map vec (apply sorted-map (range 5000))) 
[0 1] [2 3] ... [4998 4999] 

* đây là quan điểm của tôi


EDIT:

một comparason thời điểm sorted-map vs array-map

user> (time (dorun (map vec (apply sorted-map (range 500000))))) 
"Elapsed time: 391.520491 msecs" 
nil 
user> (time (dorun (map vec (apply array-map (range 500000))))) 
"Elapsed time: 674517.821669 msecs" 
+0

Cảm ơn bạn đã trả lời. Đáng buồn thay, tôi phải không vâng lời quy tắc đầu tiên của câu lạc bộ vĩ mô bởi vì nó là bắt buộc đối với "chức năng" tôi thực hiện để nhận mã không được đánh giá. Tôi không dùng macro một cách nhẹ nhàng. Tôi đã thử chức năng mảng bản đồ (cũng như sắp xếp bản đồ), nhưng nó không * thực sự * giải quyết vấn đề của tôi bởi vì sau đó mã chữ của tôi sẽ trông giống như (array-map: a 1: b 2 .. .vv) thay vì {: a 1: b 2 ... vv}. Trên thực tế, tôi có thể * tạo công việc đó, nhưng khi tôi sử dụng macro, tôi không nhất thiết phải sử dụng {} cho bản đồ, nhưng có thể phải sử dụng (mảng-bản đồ, v.v.) và tôi muốn tránh điều đó. –

1

Các vấn đề như đã nêu không hòa tan. Bản đồ được xác định là không có thứ tự; bất kỳ thứ tự nào bạn thấy trong array-map là trùng hợp ngẫu nhiên. Nếu bạn yêu cầu macro của bạn nhận được bản đồ, bạn đã mất thông tin mà bạn mong muốn.

+1

"nó thường là mong muốn để có một bản đồ mà duy trì thứ tự quan trọng. Một bản đồ mảng là một bản đồ" http://clojure.org/data_structures#Data%20Structures-ArrayMaps –

+0

Tôi không đồng ý cả với xác nhận rằng nó là mong muốn, và với hàm ý rằng nó hữu ích cho việc chuyển đổi mã. Ví dụ: '{25 (println 25), 26 (println 26), 27 (println 27), 28 (println 28), 29 (println 29), 30 (println 30), 31 (println 31), 32 (println) 32), 33 (println 33), 34 (println 34)} 'đọc dưới dạng bản đồ băm, và do đó in theo thứ tự khác với từ vựng; bảo quản thứ tự của điều đó là không thể, vì vậy nó không nên dựa vào trong mọi trường hợp. – amalloy