Tüm bu read-string fonksiyonları arasındaki ilişki hakkında net değilim. Şey, belli ki
clojure.core/read-string tarafından çıkarılan herhangi bir serileştirilmiş dizeyi okuyabilir
pr[n] ya da
print-dup. Ayrıca açıktır ki
clojure.edn/read-string göre biçimlendirilmiş dizeleri okur EDN belirtimi.
Ancak, Clojure Script ile başlıyorum ve eğer açık değil
cljs.reader/read-string uymak. Bu soru, şu şekilde serileştirilmiş bir clojure kodu yayan bir web servisine sahip olmamızla tetiklendi:
(with-out-str (binding [*print-dup* true] (prn tags)))
Bu, veri tiplerini içeren nesne serileştirmesi üretiyordu. Ancak, bu okunabilir değil
cljs.reader/read-string. Her zaman bu tip bir hatayı alıyorum:
Could not find tag parser for = in ("inst" "uuid" "queue" "js") Format should have been EDN (default)
İlk başlarda, bu hatanın atıldığını düşündüm.
cljs-ajax ama test ettikten sonra
cljs.reader/read-string bir rhino REPL içinde, aynı hatayı aldım, yani
cljs.reader/read-string kendisi. Tarafından atılır
maybe-read-tagged-type işlevi
cljs.reader ancak bunun, okuyucu sadece EDN verisi ile çalıştığı ya da ...?
Ayrıca, Clojure arasındaki farklar Belge, söylenen tek şey:
The read and read-string functions are located in the cljs.reader namespace
Hangisi aynı davranışa sahip olmaları gerektiğini gösteriyor.
Özet: Clojure, EDN'nin bir üst kümesidir. Varsayılan olarak,
pr,
prn ve
pr-strClojure veri yapıları verildiğinde geçerli EDN üretir.
*print-dup* değişiklikleri değiştirir ve onları bir gidiş-dönüşten sonra bellekteki nesnelerin "aynılığı" hakkında daha güçlü garantiler vermek için Clojure'ın tam gücünü kullanır. ClojureScript sadece, tam Clojure değil EDN okuyabilir.
Kolay çözüm: ayarlamayın
*print-dup* true ve sadece Clojure'dan ClojureScript'e giden saf verileri geçirir.
Daha zor bir çözüm: Her iki tarafta bir (muhtemelen paylaşılmış) ilgili okuyucu ile etiketlenmiş hazır sözcükleri kullanın. (Bu hala içermeyecek
*print-dup*olsa da.)
Tanjantla ilgili: EDN için çoğu kullanım vakası TransitÖzellikle ClojureScript tarafında daha hızlıdır.
Clojure bölümü ile başlayalım. Clojure, başından beri bir
clojure.core/read-string işlevi, hangi
readRead-Eval-Print-Loop'un eski Lispy anlamında bir dizgedir, yani Clojure derlemesinde kullanılan gerçek okuyucuya erişim sağlar.
Daha sonra, Rich Hickey & co, Clojure'ın veri gösterimini teşvik etmeye karar verdi ve EDN özellikleri. EDN bir alt küme Clojure; Clojure dilinin veri öğeleriyle sınırlıdır.
Clojure bir Lisp olduğundan ve tüm lisps gibi, "kodun veri koddur" felsefesine ses çıkarır, yukarıdaki paragrafın asıl sonuçları tamamen açık olmayabilir. Her yerde detaylı bir farklılık olduğundan emin değilim, ama dikkatli bir inceleme Clojure Okuyucu açıklaması ve daha önce belirtilen EDN spesifikasyonları birkaç farklılık göstermektedir. En belirgin farklılıklar makro karakterler ve özellikle de
#Clojure'da EDN'den çok daha fazla hedefi olan gönderim sembolü. Örneğin,
#(* % %) notasyon, Clojure okuyucunun aşağıdaki EDN'ye karşılık geleceği geçerli bir Clojure'dir:
(fn [x] (* x x)). Bu soru için özellikle önemli olan belgelendirilmiş
#= Okuyucunun içinde rastgele kod yürütmek için kullanılabilecek özel okuyucu makrosu.
Tam dil, Clojure okuyucusu için kullanılabilir olduğu için, okuyucunun okuduğu karakter dizisine kod yerleştirmek ve okuyucunun o anda ve oradan değerlendirilmesini sağlamak mümkündür. Birkaç örnek bulunabilir İşte.
clojure.edn/read-string işlevi tamamen Clojure dili değil, EDN formatıyla sınırlıdır. Özellikle, çalışması etkilenmez.
*read-eval* değişken ve geçerli tüm Clojure kod parçalarını okuyamaz.
Clojure okuyucusunun, çoğunlukla tarihsel nedenlerden dolayı Java'da yazılmış olduğu ortaya çıkıyor. Önemli bir yazılım parçası olduğu için, iyi çalışıyor ve büyük ölçüde hata ayıklandı ve vahşi bir şekilde aktif Clojure kullanımı birkaç yıl boyunca savaş-test edildi, Rich Hickey ClojureScript derleyicide yeniden kullanmaya karar verdi (Bu ana nedeni nedir ClojureScript derleyicisi JVM'de çalışır. ClojureScript derleme işlemi çoğunlukla Clojure okuyucusunun bulunduğu JVM'de olur ve bu nedenle ClojureScript kodu tarafından ayrıştırılır.
clojure.core/read-string (ya da onun yakın kuzeni
clojure.core/read) işlevi.
Ancak web uygulamanızın çalışan bir JVM'ye erişimi yok. ClojureScript uygulamaları için bir Java uygulaması gerektirmesi çok umut verici bir fikir gibi görünmüyordu; özellikle de ClojureScript'in temel amacı, Clojure dilinin erişimini JVM'nin (ve CLR'nin) sınırlarının ötesine uzatmaktı. Dolayısıyla ClojureScript'in kendi okuyucusuna erişemeyeceği ve dolayısıyla kendi derleyicisine erişiminin olmayacağı kararı alındı (yani,
eval ne de
read ne de
read-string ClojureScript'te). Bu karar ve etkileri daha ayrıntılı olarak tartışılmaktadır. İşteaslında şeylerin nasıl olduğunu bilen biri tarafından (orada değildim, bu nedenle bu açıklamanın tarihsel perspektifinde bazı yanlışlıklar olabilir).
Yani ClojureScript'in bir karşılığı yok
clojure.core/read-string (ve bazıları bunun gerçek bir lisp olmadığını iddia eder). Yine de, Clojure veri yapılarını bir Clojure sunucusu ile bir ClojureScript istemcisi arasında iletişim kurmanın bir yolu olması güzel olurdu ve aslında bu EDN çabasındaki motive edici faktörlerden biriydi. Sadece Clojure kısıtlanmış (ve daha güvenliokuma fonksiyonu
clojure.edn/read-string) EDN spesifikasyonunun yayınlanmasından sonra, ClojureScript standart dağıtımda EDN okuyucusunu da aldı
cljs.reader/read-string. Bu iki fonksiyonun isimleri arasında biraz daha fazla tutarlılık (veya daha ziyade ad alanları) iyi olurdu.
Nihayet orijinal sorunuzu cevaplayabilmemiz için, konuyla ilgili bir parça daha küçük bir konuya ihtiyacımız var.
*print-dup*. Bunu hatırla
*print-dup* Clojure 1.0'ın bir parçasıydı, bu da EDN, etiketlenmiş değişmezler kavramı ve kayıtlardan önce gelir. EDN ve etiketlenmiş edebi eserlerin çoğu için daha iyi bir seçenek sunduğunu iddia ediyorum
*print-dup*. Clojure genellikle birkaç veri soyutlamasının (liste, vektör, küme, harita ve her zamanki skaler) üzerine kurulduğundan, baskı / okuma döngüsünün varsayılan davranışı, verinin soyut şeklini korumaktır. harita), ancak özellikle beton türü değil. Örneğin Clojure, harita soyutlamasının çoklu uygulamalarına sahiptir. PersistentArrayMap küçük haritalar ve PersistentHashMap daha büyük olan için. Dilin varsayılan davranışı, beton türünü umursamadığınızı varsayar.
Yaptığınız nadir durumlarda ya da daha özel tipler için (zamanla deftype ya da defstruct ile tanımlanmış), bunların nasıl okunduğuna dair daha fazla kontrol isteyebilirsiniz, bu da print-dup'in amacıdır.
Nokta, ile
*print-dup* ayarlanır
true,
pr ve aile geçerli bir EDN üretmeyecek, ancak bazı açık bilgileri içeren Clojure verileri
#=(eval build-my-special-type) formları değil geçerli EDN.
[0]: "Lisps" de derleyici, karakter dizileri açısından değil, veri yapıları açısından açıkça tanımlanır. Bu, normal derleyicilerle küçük bir fark gibi görünse de (aslında karakter akışını, işlem sırasında veri yapılarına dönüştüren), Lisp'in tanımlama özelliği, okuyucu tarafından yayılan veri yapılarının, yaygın olarak kullanılan veri yapıları olmasıdır. dil. Başka bir deyişle, derleyici temel olarak sadece dilde her zaman mevcut olan bir işlevdir. Çoğu dinamik dilin bazı biçimlerini desteklediği için bu, eskiden olduğu kadar benzersiz değildir.
eval; Lisp'e özgü olan,
eval dinamik kod üretimi ve değerlendirmesini çok daha kolay hale getiren bir karakter dizisini değil, veri yapısını alır. Derleyicinin "sadece başka bir işlev" olmasının önemli bir anlamı, derleyicinin gerçekten zaten tanımlanmış ve kullanılabilir olan tüm dil ile çalıştığı ve Lisp makro sistemine giden kapıyı açan, şu ana kadar okunan tüm kodların çalıştığıdır.
cljs.reader/read sadece EDN'yi destekler, ancak
pr vb okunmayacak etiketler (özellikle protokoller ve kayıtlar için) verecektir.
Genel olarak, Clojure tarafındaysa bunu doğrulayabilirsiniz.
(= value (clojure.edn/read-string (pr-str value)))senin cljs interop çalışmalıdır. Bu, sınırlayıcı olabilir ve EDN kitaplığına geçici çözümler veya düzeltmeler hakkında bazı tartışmalar vardır.
Verilerinizin neye benzediğine bağlı olarak,
tagged açıklandığı gibi kütüphane Clojure Yemek Tarifleri.
Aslında, cljs.reader / register-tag-parser aracılığıyla özel etiket ayrıştırıcısını kaydetmek mümkün!
bir kayıt için böyle görünüyor:
(register-tag-parser! (s/replace (pr-str m/M1) "/" ".") m/map->M1)
@Gary - oldukça iyi cevap