2012-05-24 24 views
5

Daha sonra bir eval d olabilen Clojure kodunda bir Java nesnesi (bu durumda bir BufferedImage) gömmek istiyorum. kod oluşturmaClojure kodunda rastgele nesneleri gömme

çalışıyor:

(defn f [image] 
    `(.getRGB ~image 0 0)) 
=> #'user/f 

(f some-buffered-image) 
=> (.getRGB #<BufferedImage [email protected]: type = 2 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000 IntegerInterleavedRaster: width = 256 height = 256 #Bands = 4 xOff = 0 yOff = 0 dataOffset[0] 0> 0 0) 

eval çalışırken bir istisna olsun Ancak:

(eval (f some-buffered-image)) 
=> CompilerException java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: [email protected]: type = 2 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000 IntegerInterleavedRaster: width = 256 height = 256 #Bands = 4 xOff = 0 yOff = 0 dataOffset[0] 0, compiling:(NO_SOURCE_PATH:1) 

bu işin böyle bir şey yapmak için herhangi bir yolu var mı?

DÜZENLEME:

Bunu yapmaya çalışıyorum sebebi bir görüntü numuneler almakta kodu oluşturmak için mümkün istiyorum olmasıdır. Görüntü, kod nesnesini (yukarıdaki f eşdeğeri) yapan işleve iletilir, ancak (çeşitli nedenlerle) daha sonra derlenmiş kod için bir parametre olarak iletilemez.

(defn f [image] 
    (fn [] (.getRGB image 0 0))) 
+0

Sadece bu hatayı veren bir değerlendirmedir? Makrolar (örneğin "if") bunu kullanabilir, sanırım? eğer öyleyse, o zaman muhtemelen büyük olasılıkla şeyleri bir şeyleri metinden geçmeye zorladığı için (çünkü değerlendirmek için mantıklıdır). Bu sizin için bir sorunsa, gerekmediğinde değerlendirmeyi kullanıyor olabilirsiniz - bir makro ihtiyacınız olduğunda olabilir. –

+0

@andrewcooke Bunu anladığım kadarıyla, “değerlendirme” gerçekten bir şeyleri zorlamak için zorlamıyor * metin *. Eval (derleme yoluyla) nesneleri oluşturan JVM kodunu oluşturur. Metin aracılığıyla (serileştirme yoluyla) bilinmeyen nesnelerde kullanılan son çare. –

+2

@mikera Geri adım atıyorsunuz, neden alıntı ve değerlendirmeyi tercih ettiğinizi açıklayabilir misiniz? (Defn f [a] (fn [] (.getRGB a 0 0))) '? – user100464

cevap

2

değil ihtiyaç, ancak aşağıdaki hile kullanarak keyfi bir nesneye evals kod oluşturabilir emin: Sonra

(def objs (atom [])) 


(defn make-code-that-evals-to [x] 
    (let [ 
     nobjs (swap! objs #(conj % x)) 
     i (dec (count nobjs))] 
    `(nth ~i @objs))) 

şunları yapabilirsiniz: Bu sadece bir

> (eval (make-code-that-evals-to *out*)) 
#<PrintWriter [email protected]> 

olduğunu kavramın ispatı ve üretilen objeleri sızdırıyor - değerlendirmeyi referans üzerinde kaldıran bir kod üretebiliyorsunuz, ancak bunu yalnızca bir kez değerlendirebiliyordunuz.

Düzenleme: (! Kötü) bir sızıntı izleyerek önlenebilir kesmek:

Yukarıdaki kod kodu oluşturulur zamanda harici nesne başvurusu depolayarak Eval en derleyici atlar. Bu ertelenebilir. Nesne referansı, derleyici bir makro tarafından baypas edilerek oluşturulan kodda saklanabilir. Referansı kodda saklamak, çöp toplayıcısının normal çalıştığı anlamına gelir.

Anahtar, nesneyi saran makrodur. Özgün çözümün yaptığı şeyi yapar (yani, nesneyi derleyiciyi atlamak için harici olarak depolar), ancak derlemeden hemen önce. Oluşturulan ifade dış referansı alır, ardından sızıntıları önlemek için siler.

Not: Bu kötü dur. Makroların genişleme zamanı, küresel yan etkilerin ortaya çıkması için en az istenen yer ve bu çözümün tam olarak ne olduğu.kodu için Şimdi

: geçici olarak benzersiz anahtarlar (sözlük) anahtarlı nesneleri depolamak nerede

(def objs (atom {})) 

burada.

(defmacro objwrap [x sym] 
    (do 
    (swap! objs #(assoc % sym x)) ; Global side-effect in macro expansion 
    `(let [o# (@objs ~sym)] 
     (do 
     (swap! objs #(dissoc % ~sym)) 
     o#)))) 

Bu x nesne referans ve sym eşsiz anahtar tutarak üretilen kod oturur kötü makro. Derleme işleminden önce, nesneyi dış sözlükte sym anahtarının altında depolar ve onu alan kodu üretir, dış referansı siler ve alınan nesneyi döndürür.

(defn make-code-that-evals-to [x] 
    (let [s 17] ; please replace 17 with a generated unique key. I was lazy here. 
    `(objwrap ~x ~s))) 

Hiçbir şey fantezi değil, yalnızca tek bir anahtarla birlikte kötü makrodaki nesneyi sarın.

Elbette, yalnızca sonucu değerlendirmeden makroyu genişletirseniz, hala bir sızıntı elde edersiniz.

+0

güzel bir fikir!ama ben bellek sızıntısı katılıyorum bu biraz iğrenç yapar – mikera

+0

@mikera Nasıl tamir edeceğime dair bir fikrim var, zaman izin verir düzenler :) –

+0

@mikera Çözüm eklendi. Bunun için hala bir yol ararım, çünkü bu tahıllara karşı çıkıyor gibi görünüyor. –

3

sanırım:

Ben dolayısıyla ben sadece böyle bir şey yapamaz, bu oluşturulan koda başka dönüşümleri uygular çok daha büyük bir kod üretme kütüphanesinin parçası olduğu için alıntı kodu oluşturmak gerekiyor derleme zamanında nesneyi (veya gerekli nesneyi oluşturmanın bir yolunu) alan bir makro yazmanız gerekir, bu nesneyi ikili biçiminde (bayt dizisi) serileştirin ve makronun çıktısı olmalıdır. bayt dizisi ve serileştirilmiş verilerden nesneyi serileştirerek elde etmek için kullanılabilecek bir işlev.

+0

Serileştirme neden gereklidir? Derlenmiş kod zaten harici bayt dizisine bağlıdır, bu yüzden neden bir nesne dizisi yapıp sadece oradaki orijinal nesneyi referans olarak tutmayın? –

+0

Temelde, makro derleme zamanı olacak şekilde değerlendirileceği zaman, ex: '(embed-resource" my-file.jpeg ")' için, makro gömülü kaynak dosyayı okuyacak ve kodda bir java dizisi olarak saklayacaktır. Bu, görüntüyü kod içine gömmenize izin verecektir – Ankur

+0

Teşekkürler, şimdi anlıyorum. Doğru bir şekilde anlarsam, kodu oluştururken (OP'nin örneğinde 'f' işlevinde) nesneyi hemen seri hale getirebilirsiniz, değil mi? –

0

neden: (defmacro m [img] `(.getRGB ~ img 0 0)) sonra u yazabilir: fark f fonksiyonu olmasıdır

(m, bazı tamponlu görüntü) Bu yüzden argümanı, bedeni değerlendirilmeden önce değerlendirilecektir. Böylece görüntü nesnesinin kendisi oluşturulan kodun içine yerleştirilecektir. Ancak makrolar için argümanları değerlendirilmeyecek. Bu nedenle, yalnızca sembolün bazı tamponlanmış resmi kod içerisine yerleştirilecektir. Oluşturulan kod: (.getRGB bazı tamponlu görüntü 0 0) olacaktır. Tıpkı kaynak kodunu direkt yazmak gibi. Bence istediğin bu.

Peki neden oluşturulan kodda bir nesne yerleştiremiyorum? Cevap: evet, yapabilirsin. İstisna mesajının söylediği şey gerçek değildir. Oluşturulan kodda bazı nesneler yerleştirebiliriz, ancak bunların her türlü değil. Sembol, sayı, karakter, dize, regex patten, anahtar kelime, boole, liste, harita, set vb. Içerirler. Tüm bu nesneler Clojure derleyicisi tarafından anlaşılacaktır. Diğer dillerdeki anahtar kelimeler, operatörler ve edebi türler gibidir. Clojure derleyicisinin her türlü nesneyi bilmesini gerektiremezsiniz, tıpkı bir C veya Java derleyicisinin gerektiremeyeceği gibi, sözdizimi tarafından bulunmayan tüm kelimeleri bilir.