Saf işlevin faydaları


82

Bugün saf işlev hakkında okuyordum, kullanımıyla karıştırıldım:

Aynı girdi kümesi için aynı değer kümesini döndüren ve gözlemlenebilir herhangi bir yan etkisi olmayan bir işlevin saf olduğu söylenir.

örneğin strlen()saf bir işlev iken rand()saf olmayan bir işlevdir .

http://ideone.com/33XJU

Yukarıdaki program, purebildirim yokluğunda olduğu gibi davranır .

Bir işlevi pure[çıktıda değişiklik yoksa] olarak bildirmenin faydaları nelerdir ?


7
Evet - oluşturulan montaja bakın.
Philip Kendall

4
Bu saflık tanımının doğru olduğunu sanmıyorum - printförneğin, niteleyebilir (aynı argümanlarla iki kez çağırmak aynı dönüş değerini verir), ancak saf değildir.
tdammers

14
@tdammers: Gerçekten, ...and no side-effects...parçası yok.
Frerich Raabe

2
@Ben: Entropi nereden geliyor? Burada (teorik olarak) deterministik makinelerle uğraşıyoruz, onlara gerçek entropi sağlamanın tek yolu dış kaynaklardan geliyor, bu da yan etkiler anlamına geliyor. Elbette, teknik yan etkilerin orada olmadığını ve işlevlerin gerçekten belirleyici olmadığını varsayarak, programlama dillerinin kesin olmayan işlevleri tanımlamasına izin verebiliriz; ancak bunu yaparsak, saflığı izlemenin pratik faydalarının çoğu kaybolur.
tdammers

3
tdammers doğrudur - yukarıda verilen saf tanımı yanlıştır. Pure, çıktının yalnızca işlevin girdilerine bağlı olduğu anlamına gelir ; ayrıca, gözlemlenebilir hiçbir yan etki olmamalıdır. "Aynı girdi için aynı çıktı" bu gereksinimlerin çok yanlış bir özetidir. en.wikipedia.org/wiki/Pure_function
Dancrumb

Yanıtlar:


145

pure derleyicinin işlev hakkında belirli optimizasyonlar yapabileceğini bilmesini sağlar: aşağıdaki gibi bir kod hayal edin:

Saf bir işlevle, derleyici fun(10)1000 kez değil, yalnızca bir kez değerlendirmesi gerektiğini bilebilir . Karmaşık bir işlev için bu büyük bir kazançtır.


Yani, not almayı güvenle kullanabilirsiniz
Joel Coehoorn

@mob Ne demek istiyorsun? Neden olmasın?
Konrad Rudolph

15
Çünkü dizgiyi (bir adresten başlayan karakter dizisini) girdiyi (dizginin başladığı adrese işaretçi) değiştirmeden değiştirebilirsiniz, yani onu hafızaya alamazsınız. Bu, değişmez dizeleri olan bir dilde yalnızca saf bir işlev olacaktır (örneğin Java).
mob

5
@KonradRudolph: 1000 uzunluğunda bir dizi düşünün. Çağrı strlenüzerine. Sonra tekrardan. Aynı şey evet mi? Şimdi ikinci karakteri olacak şekilde değiştirin \0. Does strlenhala şimdi 1000 return? Başlangıç ​​adresi aynıdır (== giriş aynıdır) ancak işlev şimdi farklı bir değer döndürür.
Mike Bailey

5
@mob Bu iyi bir itiraz, tabii ki haklısın. Kitapların bilestrlen (GCC / glibc'de) aslında saf olduğunu iddia etmeleri beni yanılttı . Ancak glibc uygulamasına bir bakış bunun yanlış olduğunu gösterdi.
Konrad Rudolph

34

Bir işlevin 'saf' olduğunu söylediğinizde, dışarıdan görünür yan etkilerinin olmadığını garanti etmiş olursunuz (ve bir yorumun dediği gibi, eğer yalan söylerseniz, kötü şeyler olabilir). Bir fonksiyonun 'saf' olduğunu bilmek, bu bilgiyi belirli optimizasyonları yapmak için kullanabilen derleyici için faydalara sahiptir.

İşte budur GCC belgeleri hakkında söylediği pureözniteliği:

saf

Birçok fonksiyonun dönüş değeri dışında hiçbir etkisi yoktur ve bunların dönüş değeri sadece parametrelere ve / veya global değişkenlere bağlıdır. Böyle bir fonksiyon, bir aritmetik operatörün yapacağı gibi, ortak alt ifade eliminasyonuna ve döngü optimizasyonuna tabi olabilir. Bu işlevler, pure niteliği ile bildirilmelidir. Örneğin,

Philip'in cevabı zaten bir fonksiyonun 'saf' olduğunu bilmenin döngü optimizasyonlarına nasıl yardımcı olabileceğini gösteriyor.

Aşağıda, genel alt ifade eliminasyonu için bir tane verilmiştir (verilen foosaftır):

Olabilir:


3
Herhangi birinin bunu yapıp yapmadığından emin değilim, ancak saf işlevler aynı zamanda derleyicinin işlev çağrıldığında yeniden sıralama yapmasına izin verir, yeniden sıralamanın yararlı olacağını düşünürse. Yan etkilerin ortaya çıkma olasılığı olduğunda, derleyicinin daha muhafazakar olması gerekir.
mpdonadio

@MPD - Evet, kulağa mantıklı geliyor. Ve bir calltalimat, süper skalar CPU'lar için bir darboğaz olduğundan, derleyiciden bazı yardımlar yardımcı olabilir.
ArjunShankar

Birkaç yıl önce, bu tekniği er ya da geç dönüş değerlerini elde etmek için kullanan bir DSP derleyicisini kullandığımı belli belirsiz hatırlıyorum. Bu, boru hattı duraklamalarını en aza indirmesine izin verdi.
mpdonadio

1
99 bir sabit olduğundan ve foo her zaman aynı sonucu döndüreceğinden "foo (99)" önceden hesaplanabilir mi? Belki bir tür iki aşamalı derlemede?
markwatson

1
@markwatson - Emin değilim. Bunun mümkün olmadığı durumlar olabilir. örneğin foo, başka bir derleme biriminin parçasıysa (başka bir C dosyası) veya önceden derlenmiş bir kitaplıktaysa. Her iki durumda da, derleyici ne yaptığını bilemez foove önceden hesaplayamaz.
ArjunShankar

29

Olası çalışma zamanı avantajlarına ek olarak, saf bir işlevin kodu okurken akıl yürütmesi çok daha kolaydır. Ayrıca, dönüş değerinin yalnızca parametrelerin değerlerine bağlı olduğunu bildiğiniz için saf bir işlevi test etmek çok daha kolaydır.


3
+1, test etme konusundaki düşünceniz ilginç. Kurulum ve yırtılma gerekmez.
ArjunShankar

15

Saf olmayan bir işlev

saf bir işlevin uzantısı gibidir

Burada, açık fonksiyon argümanlarının yanı sıra x, y, evrenin geri kalanı (veya bilgisayarınızın iletişim kurabileceği herhangi bir şey) örtük bir potansiyel girdi olarak var. Benzer şekilde, açık tamsayı dönüş değerinin yanı sıra, bilgisayarınızın yazabileceği her şey, dolaylı olarak dönüş değerinin bir parçasıdır.

Saf bir işlev hakkında akıl yürütmenin neden saf olmayan bir işlevden çok daha kolay olduğu açık olmalıdır.


1
+1: Evreni potansiyel bir girdi olarak kullanmak, saf ve saf olmayan arasındaki farkı açıklamanın çok güzel bir yoludur.
ArjunShankar

gerçekten de monadların arkasındaki fikir budur.
Kristopher Micinski

7

Bir eklenti olarak, C ++ 11'in bazı şeyleri constexpr anahtar sözcüğünü kullanarak kodladığını belirtmek isterim. Misal:

Constexpr kullanımındaki kısıtlamalar, işlevin kanıtlanabilir şekilde saf olmasını sağlar. Bu şekilde, derleyici daha agresif bir şekilde optimize edebilir (sadece kuyruk özyinelemesini kullandığınızdan emin olun, lütfen!) Ve işlevi çalışma zamanı yerine derleme zamanında değerlendirebilir.

Öyleyse, sorunuza cevap vermek gerekirse, eğer C ++ kullanıyorsanız (C dediniz biliyorum ama bunlar birbiriyle ilişkili), doğru tarzda saf bir işlev yazmak, derleyicinin işlevle her türlü harika şeyi yapmasına olanak tanır: -)


4

Genel olarak, Pure işlevlerinin, derleyicinin yararlanabileceği, saf olmayan işlevlere göre 3 avantajı vardır:

Önbelleğe almak

Diyelim ki saf işleve sahipsin f 100000 kez çağrılan var, çünkü bu deterministik ve sadece parametrelerine bağlı olduğundan, derleyici değerini bir kez hesaplayabilir ve gerektiğinde kullanabilir.

Paralellik

Saf fonksiyonlar herhangi bir paylaşılan hafızayı okumaz veya bu hafızaya yazmaz ve bu nedenle herhangi bir beklenmedik sonuç olmaksızın ayrı iş parçacıkları içinde çalışabilir.

Referansla Geçme

Bir işlev f(struct t)argümanını tdeğere göre alır ve diğer yandan, derleyici , değerinin değişmeyeceğini ve performans kazanımlarına sahip olmayacağını garanti ederken, saf olarak ilan edilip edilmediğine treferansla geçebilir .ft


Derleme zamanına ek olarak, saf fonksiyonlar oldukça kolay bir şekilde test edilebilir: sadece çağırın.

DB'lere / dosya sistemine nesneler veya sahte bağlantılar oluşturmaya gerek yok.

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.