İkame modelini kabaca anladığım için (referans şeffaflığı (RT) ile), bir işlevi en basit parçalarına ayırabilirsiniz. İfade RT ise, ifadeyi kaldırabilir ve her zaman aynı sonucu alabilirsiniz.
Evet, sezgi oldukça doğru. Daha kesin olmak için birkaç işaret:
Dediğiniz gibi, herhangi bir RT ifadesinin bir single
"sonucu" olmalıdır. Yani, factorial(5)
programda bir ifade verildiğinde , her zaman aynı "sonucu" vermelidir. Bu nedenle, factorial(5)
programda belirli bir değer varsa ve 120 verirse, zamana bakılmaksızın hangi "adım sırası" genişletildiği / hesaplandığından bağımsız olarak daima 120 vermelidir .
Örnek: factorial
işlev.
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
Bu açıklama ile ilgili birkaç husus vardır.
Her şeyden önce, farklı değerlendirme modellerinin (bkz. Uygulanabilir veya normal sıraya bakın) aynı RT ifadesi için farklı "sonuçlar" verebileceğini unutmayın.
def first(y, z):
return y
def second(x):
return second(x)
first(2, second(3)) # result depends on eval. model
Yukarıdaki kodda first
ve second
referans olarak şeffaftır ve yine de, sondaki ifade, normal düzen ve uygulanabilir düzen altında değerlendirildiğinde farklı "sonuçlar" verir (ikincisinin altında, ifade durmaz).
.... tırnak içinde "sonuç" kullanımına yol açar. Bir ifadenin durması gerekmediğinden, bir değer üretmeyebilir. Yani "sonuç" kullanmak biraz bulanık. Bir RT ifadesinin computations
bir değerlendirme modeli altında her zaman aynı sonucu verdiği söylenebilir .
Üçüncüsü, foo(50)
programda farklı yerlerde iki ifadenin farklı ifadeler olarak görünmesi gerekebilir - her biri birbirinden farklı olabilecek kendi sonuçlarını verir. Örneğin, dil dinamik kapsama izin veriyorsa, her iki ifade de, sözcüksel olarak özdeş olsa da, farklıdır. Perl dilinde:
sub foo {
my $x = shift;
return $x + $y; # y is dynamic scope var
}
sub a {
local $y = 10;
return &foo(50); # expanded to 60
}
sub b {
local $y = 20;
return &foo(50); # expanded to 70
}
Dinamik kapsam misleads o kadar kolay bir düşünmek için yapmak çünkü x
tek girdidir foo
gerçekte, o zaman, x
ve y
. Farkı görmenin bir yolu, programı dinamik kapsamı olmayan eşdeğer bir programa dönüştürmektir - yani, parametreleri açıkça geçirerek, tanımlamak yerine , arayanları açıkça foo(x)
tanımlar foo(x, y)
ve y
iletiriz.
Mesele şu ki, her zaman bir function
zihniyet altındayız : bir ifade için belirli bir girdi verildiğinde, buna karşılık gelen bir "sonuç" verilir. Aynı girdiyi verirsek, her zaman aynı "sonucu" beklemeliyiz.
Şimdi, aşağıdaki kod ne olacak?
def foo():
global y
y = y + 1
return y
y = 10
foo() # yields 11
foo() # yields 12
Yeniden foo
tanımlamalar olduğundan prosedür RT'yi keser. Yani, y
bir noktada tanımladık ve ikincisi de aynı şeyi yeniden tanımladık y
. Yukarıdaki perl örneğinde, y
s, aynı "y" harf adını paylaşsalar da farklı bağlardır. Burada y
s aslında aynı. Bu yüzden atamanın bir meta işlem olduğunu söylüyoruz : aslında programınızın tanımını değiştiriyorsunuz.
Kabaca, insanlar genellikle farkı şu şekilde tasvir eder: yan etkisi olmayan bir ortamda, bir eşlemeniz vardır input -> output
. "Zorunlu" bir ortamda, zaman input -> ouput
içinde state
değişebilen bir bağlamda var .
Şimdi, ifadeleri sadece karşılık gelen değerleri yerine koymak yerine state
, bunu gerektiren her işlemde de dönüşümler uygulanmalıdır (ve tabii ki ifadeler state
hesaplamaları gerçekleştirmek için buna danışabilir ).
Dolayısıyla, bir yan etki serbest programında, bir ifadeyi hesaplamak için bilmemiz gereken tek şey onun bireysel girdisidir, zorunlu bir programda, her bir hesaplama adımı için girdileri ve tüm durumu bilmemiz gerekir. Akıl yürütme ilk kez büyük bir darbe çekiyor (şimdi, sorunlu bir prosedürde hata ayıklamak için, girdiye ve çekirdek dökümü gerekir). Bazı numaralar ezberleme gibi pratik değildir. Ama aynı zamanda, eşzamanlılık ve paralellik çok daha zorlaşıyor.
RT
kullanmasını devre dışı bırakır sizisubstitution model.
ile büyük bir sorun değil kullanmak mümkün olansubstitution model
bir program hakkında nedenden için kullanarak gücüdür?