2013-08-27 1 views
4

clojure profiling library에는 프로파일 링 정보를 저장하는 아톰이 있으며 여러 함수로 수정됩니다. 주석에서 그들은 요약 통계 (함수 중 하나)가 효율성을 위해 마지막으로 호출되었다고 주장하지만 실제 코드에서 이것이 어떻게 수행되었는지는 알 수 없습니다.Clojure Maps, 키 값 생성 순서

그런 다음이 방법을 적용 할 수있는 방법 중 하나는지도를 만드는 과정에서의 순서라는 것을 알았 기 때문에 설명하기에 더 간단한 예제를 다시 만들었습니다.

(defn t [] 
    (let [a (atom {})] 
    {:b (swap! a #(assoc % :data 'is-here)) 
    :c (keys @a)})) 

여기에 코멘트와 일치하여 : b 또는 : c 중 하나가 코드의 첫 번째에옵니다. 물론 순서가 있어야하지만,이 동작이 보장됩니까? 정렬되지 않은 해시는 순서가 없기 때문에 병렬 처리에 해로운 영향을 미칠 수 있기 때문에 그렇게해서는 안됩니다.

+0

뭔가 다른 발견, 알고 보니는 알파벳에 따라 달라집니다 키의 순서, 아마도 그들이 어떻게 든 정렬되는 방식. 나는. aboce 예제에서 키가 {: d (스왑! ...) : a (keys ...)} 인 경우 동작이 다릅니다. – zenna

+0

실제로 그것은 단지 그 행동이 이상하지 않고, 그것에 의존하지 않을 것입니다. – zenna

+0

당신은 pdata-stats를 언급하고 있습니까? pdata-stats에 대한 인수는 변경할 수 없기 때문에 맵 키가 해당 함수 내에서 생성되는 순서는 무관합니다. – noisesmith

답변

2

{...} 양식이 8 개의 맵 엔트리 (키/값 쌍)와 동일하거나 그 이하로 유지되는 한, 주문은 유지됩니다. {...}은 8 개 이하의 항목이있는 PersistentArrayMap이되며 그렇지 않은 경우 PersistentHashMap이됩니다. 전자는 맵 엔트리의 주어진 순서를 보존 할 것이고 보증은 후자로 확장되지 않는다. Source.

user=> (let [x (atom 0)] 
     {:a (do (Thread/sleep 1000) (swap! x inc)) 
      :b (swap! x inc)}) 
{:a 1, :b 2} 

그러나 다른에서 평가할 수 :

은 병렬 처리에 관해서는, 나는 다음과 같은 간단한 테스트 맵 항목이 8 개 이하의 항목이 만든지도를 위해, 그들은 주어진 순서대로 평가받을 것이라는 점을 보여줍니다 생각 이상 8 개 항목으로 만든지도하기 위해서는 :

user=> (let [x (atom 0)] 
     {:a (do (Thread/sleep 1000) (swap! x inc)) 
      :b (swap! x inc) 
      :c (swap! x inc) 
      :d (swap! x inc) 
      :e (swap! x inc) 
      :f (swap! x inc) 
      :g (swap! x inc) 
      :h (swap! x inc) 
      :i (swap! x inc)}) 
{:a 1, :c 2, :b 3, :f 4, :g 5, :d 6, :e 7, :i 8, :h 9} 

비록, 적어도 9 개 항목에서 해시 맵, 그것은 어떤 병렬 아닌 것 같아 자신의 인스턴스화가 동안 진행된다. 그 흥미 롭군요.

3

지도 리터럴의 평가 순서에 구현 세부 사항을 고려하고지도 리터럴에 부작용 (예 : 원자 상태 설정)이있는 상수가 아닌 표현식을 사용하여 문제를 묻는 방법을 생각해 보겠습니다.

잘 정의 된 평가 의미에 대해서는 함수 호출을 사용하십시오. 여기서 인수는 왼쪽에서 오른쪽으로 평가되는 것이 보장됩니다.

(let [i (atom 0)] 
    (hash-map :a (swap! i inc) :b (swap! i inc) :c (swap! i inc))) 
;=> {:a 1, :c 3, :b 2} 

해시 맵을 사용했기 때문에 키 순서가 맞지 않지만 값은 작성된 순서대로 키에 해당합니다.

  • 독자가 순서 배열지도로 평가되지 않은지도 리터럴을 취급 :

    구현 세부 사항

    (버전 1.5)지도 리터럴의 구현 세부 사항은 몇 가지에 따라 달라집니다 작은지도 (8 쌍 이하) 또는 큰지도에 대한 정렬되지 않은 해시지도.

  • 컴파일러 평가 기는 키와 값이 상수 식인 경우 정렬되지 않은 해시 맵으로 판독기가 제공하는 맵 식을 구문 분석하지만이를 배열 맵으로 평가합니다. 그렇지 않으면 컴파일러 평가 기는 크기에 따라 독자가 제공하는 키 순서로 평가합니다.

작은 예는이 것 좀 명확하게 (아마도) :

user=> {:a 1, :b 2, :c 3} 
{:a 1, :c 3, :b 2} 
user=> (type *1) 
clojure.lang.PersistentArrayMap 

user=> (def m1 {:a 1, :b 2, :c 3}) 
#'user/m1 
user=> m1 
{:a 1, :c 3, :b 2} 
user=> (type m1) 
clojure.lang.PersistentHashMap 
user=> (eval m1) 
{:a 1, :c 3, :b 2} 
user=> (type *1) 
clojure.lang.PersistentArrayMap 

하지만를 ...

user=> (def m2 {:a ((fn [] 1)), :b 2, :c 3}) 
#'user/m2 
user=> m2 
{:a 1, :b 2, :c 3} 
user=> (type m2) 
clojure.lang.PersistentArrayMap