Eğer değişkenleri yeniden tanımlamak için def kullanabilirsinizse, bu nasıl değişmez olarak değerlendirilir?


10

Clojure'u öğrenmeye çalıştığınızda yardım edemezsiniz, ancak Clojure'un tamamen değişmez verilerle nasıl ilgili olduğu sürekli olarak söylenir. Fakat bir değişkeni defdoğru kullanarak yeniden tanımlayabilirsiniz. Clojure geliştiricilerinin bundan kaçındığını anlıyorum, ancak herhangi bir dilde değişkenleri aynı şekilde değiştirmekten kaçınabilirsiniz. Birisi bana bunun nasıl farklı olduğunu açıklayabilir mi, çünkü okuduğum derslerden ve kitaplardan eksik olduğumu düşünüyorum.

Örnek vermek gerekirse

a = 1
a = 2

Ruby'den (veya isterseniz blub'dan)

(def a 1)
(def a 2)

Clojure bölgesinde bulundunuz mu?

Yanıtlar:


9

Daha önce fark ettiğiniz gibi, Clojure'da değişebilirliğin cesaret kırılması, yasak olduğu ve onu destekleyen hiçbir yapı olmadığı anlamına gelmez. Bu nedenle def, kullanımınızı ortamdaki bir bağlayıcıyı diğer dillerde yapılan ödeve benzer şekilde değiştirebilir / değiştirebilirsiniz ( vars hakkındaki Clojure belgelerine bakın ). Global ortamda bağlantıları değiştirerek, bu bağlantıları kullanan veri nesnelerini de değiştirirsiniz. Örneğin:

user=> (def x 1)
#'user/x
user=> (defn f [y] (+ x y))
#'user/f
user=> (f 1)
2
user=> (def x 100)
#'user/x
user=> (f 1)
101

Bağlamayı yeniden tanımladıktan sonra x, işlevinin fde değiştiğine dikkat edin , çünkü vücudu bu bağlamayı kullanır.

Bunu, bir değişkeni yeniden tanımlamanın eski bağlamayı silmediği, yalnızca gölgelediği , yani yeni tanımdan sonra gelen kapsamda görünmez kıldığı dillerle karşılaştırın . SML REPL'e aynı kodu yazarsanız ne olacağını görün:

- val x = 1;
val x = 1 : int
- fun f y = x + y;
val f = fn : int -> int
- f 1;
val it = 2 : int
- val x = 100;
val x = 100 : int
- f 1;
val it = 2 : int

İkinci tanımından sonra, xişlevin tanımlandığı sırada fhala x = 1kapsamda olan bağlamayı kullandığına , yani bağlamanın val x = 100önceki bağlamanın üzerine yazmadığına dikkat edin val x = 1.

Alt satır: Clojure, küresel ortamı değiştirmeye ve içindeki bağları yeniden tanımlamaya izin verir. SML gibi diğer diller gibi bundan kaçınmak mümkün olabilir, ancak defClojure'daki yapı küresel bir ortama erişmek ve değiştirmek anlamına gelir. Uygulamada bu, Java, C ++, Python gibi zorunlu dillerde atamanın yapabileceklerine çok benzer.

Yine de, Clojure mutasyondan kaçınan birçok yapı ve kütüphane sağlar ve onu kullanmadan uzun bir yol kat edebilirsiniz. Mutasyondan kaçınmak Clojure'da tercih edilen programlama stilidir.


1
Mutasyondan kaçınmak, tercih edilen programlama stilidir. Bu ifadenin bugünlerde her dil için geçerli olmasını öneririm; sadece Clojure;)
David Arno

2

Clojure tamamen değişmez verilerle ilgilidir

Clojure, mutasyon noktalarını (yani, s, s, s ve s) kontrol ederek değişebilir durumu yönetmekle ilgilidir . Tabii ki, birlikte çalışma yoluyla kullandığınız herhangi bir Java kodu istediği gibi yapabilir.RefAtomAgentVar

Ancak def doğru kullanarak bir değişkeni kolayca yeniden tanımlayabilirsiniz?

A'yı Var(örneğin, yerel bir değişkenin aksine) farklı bir değere bağlamak istiyorsanız , evet. Aslında, Vars ve Global Ortamda belirtildiği gibi , Vars, özellikle Clojure'un dört "referans türünden" biri olarak dahil edilmiştir (gerçi, esas olarak orada dinamik olanlara atıfta bulunduğunu söyleyebilirim Var).

Lisps ile REPL aracılığıyla interaktif, keşifsel programlama faaliyetleri yürütmek için uzun bir geçmiş var. Bu genellikle eski değişkenleri yeniden tanımlamanın yanı sıra yeni değişkenleri ve işlevleri tanımlamayı da içerir. Ancak, REPL dışında def, a Varformunun zayıf olduğu düşünülmektedir.


1

Gönderen Brave ve true için Clojure

Örneğin, Ruby'de değerini oluşturmak için bir değişkene birden çok atama yapabilirsiniz:

severity = :mild
  error_message = "OH GOD! IT'S A DISASTER! WE'RE "
  if severity == :mild
    error_message = error_message + "MILDLY INCONVENIENCED!"
  else
    error_message = error_message + "DOOOOOOOMED!"
  end

Clojure'da benzer bir şey yapmaya cazip olabilirsiniz:

(def severity :mild)
  (def error-message "OH GOD! IT'S A DISASTER! WE'RE ")
  (if (= severity :mild)
      (def error-message (str error-message "MILDLY INCONVENIENCED!"))
  (def error-message (str error-message "DOOOOOOOMED!")))

Bununla birlikte, böyle bir adla ilişkilendirilen değeri değiştirmek, programınızın davranışını anlamayı zorlaştırabilir, çünkü hangi değerin bir adla ilişkili olduğunu veya bu değerin neden değişmiş olabileceğini bilmek daha zordur. Clojure, değişiklikle başa çıkmak için Bölüm 10'da öğreneceğiniz bir dizi araca sahiptir. Clojure'u öğrendikçe, nadiren bir ad / değer ilişkilendirmesini değiştirmeniz gerektiğini görürsünüz. Önceki kodu yazmanın bir yolu:

(defn error-message [severity]
   (str "OH GOD! IT'S A DISASTER! WE'RE "
   (if (= severity :mild)
     "MILDLY INCONVENIENCED!"
     "DOOOOOOOMED!")))

(error-message :mild)
  ; => "OH GOD! IT'S A DISASTER! WE'RE MILDLY INCONVENIENCED!"

Aynı şeyi Ruby'de kolayca yapamaz mıydın? Verilen öneri, bir değer döndüren bir işlevi tanımlamaktır. Ruby'nin de işlevleri var!
Evan Zamir

Evet biliyorum. Ancak Clojure, önerilen problemi çözmenin zorunlu bir yolunu teşvik etmek yerine (ciltleri değiştirmek gibi) işlevsel paradigmayı benimser.
Tiago Dall'Oca
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.