2009-07-22 13 views
6

Bir öğenin listede kaç kez göründüğünü belirten 3 işlev yazdım. Çeşitli girdiler denedim ve profil oluşturdum ancak yığın kullanım verimliliği ve zaman verimliliği açısından hangi işlevin en iyi olduğunu hala bilmiyorum. Lütfen bana yardım edin. derleyici/interperter kuyruk özyinelemenin için optimize edileceği, böyleceYığın Kullanım Verimliliği ve Zaman açısından en iyi işlev hangisidir?

;; Using an accumulator 
    (defn count-instances1 [a-list an-element] 
     (letfn [(count-aux [list-aux acc] 
         (cond 
          (empty? list-aux) acc 
          :else (if (= (first list-aux) an-element) 
            (count-aux (rest list-aux) (inc acc)) 
            (count-aux (rest list-aux) acc))))] 
     (count-aux a-list 0))) 

;; Normal counting 
    (defn count-instances2 [a-list an-element] 
    (cond 
     (empty? a-list) 0 
     :else 
      (if (= (first a-list) an-element) 
       (+ 1 (count-instances2 (rest a-list) an-element)) 
       (count-instances2 (rest a-list) an-element)))) 

;; using loop. does this help at all? 
    (defn count-instances3 [a-list an-element] 
     (loop [mylist a-list acount 0] 
      (if (empty? mylist) 
       acount 
       (if (= (first mylist) an-element) 
       (recur (rest mylist)(inc acount)) 
       (recur (rest mylist) acount))))) 
+3

Profil oluşturma çabalarınızın sonuçları neydi? –

+3

İç içe “defn” muhtemelen düşündüğünüzü yapmaz. 'defn' her zaman bir üst seviye işlevi tanımlar. Bir iç işlevi tanımlamak istiyorsanız 'letfn' (veya hatta' (let [f (fn ...)]) ') kullanabilirsiniz. –

+0

Teşekkürler Brian. Ama çalışmasına izin veremiyorum. Sorumu letfn ile düzenler misiniz? Çok teşekkürler. – unj2

cevap

2

döngü/tekrarlanmasını versiyonu doğru yoldur. Clojure, JVM'nin sınırlamaları nedeniyle kuyruk çağrılarını optimize edemez.

+3

Bu doğru değil. Clojure * 'un kuyruk aramalarını optimize etmediğini * söylemelisiniz, çünkü zaten sahip olmayan bir dilde (Java) elde etmek oldukça zor. Aslında, JVM'nin üzerinde kuyruk aramalarını optimize eden bazı dil uygulamaları (örneğin, SISC - http://sisc-scheme.org/) bulunmaktadır. –

+0

Bu gerçekten garip. Neden kuyruk aramalarını optimize etmek istemiyor? Bizi bir sürü güçlükten kurtarır mıydı? Ticaret var mı? – unj2

+3

'recur' güzeldir çünkü açık ve sadece kuyruk konumlarından (aksi takdirde derleyici şikayette bulunur) kullanabilirsiniz. Her şey otomatik olarak kesilebilir, ancak işlev adınızı 'nüks' sembolü ile kuyruk çağrısında değiştirmek pek de zor değil. –

0

kodunuzu yazma, bazı performans artışa yol ve kullanım azaltma yığını olmalıdır. Bence normal sayma fonksiyonunun kuyruk özendirmesi için uygun olabileceğini düşünüyorum, bu yüzden birinin hızlı olması gerekir. Sadece Lisp'de bir hobi olarak oynadığımdan emin değilim.

http://en.wikipedia.org/wiki/Tail_recursion

+0

Clojure, JVM'nin sınırlamaları nedeniyle kuyruk çağrılarını optimize edemez. – Svante

+1

Zengin Hickey'nin bu konudaki yorumu, her zaman (JVM'de bunu yapmanın karmaşıklığı nedeniyle) neredeyse her zaman işe yarayan bir örtüşmeden (nüks) çalışan açık bir abstactyona sahip olmanın daha iyi olmasıydı. –

+0

@Svante - Clojure kuyruk aramalarını optimize edebilir ve yapar. Sadece 'recur' (Rich Hickey tarafından bir dil tasarımı tercih edildi) kullanarak istediğinizi açıkça belirtmek zorundasınız. Çoğu zaman JVM'de TCO yapmak mümkün. JVM sınırlamaları sadece karşılıklı ortaklaşmayı etkiler (aslında oldukça nadir bir durumdur). – mikera

İlgili konular