Neden bugün () saf olmayan bir fonksiyon örneği?


38

Görünen o ki, "saf fonksiyonlar" hakkındaki bu Wikipedia makalesi gibi bir şey okurken , Today()saf olmayan bir fonksiyonun bir örneği olarak listeleniyor ama benim için oldukça saf görünüyor. Resmi bir giriş argümanı olmadığı için mi? Neden günün gerçek zamanı "işleve girdi" olarak işlem görmedi, bu durumda eğer aynı girişi yaptıysanız, yani today()aynı anda iki kez çalıştırıldıysanız veya tekrar yürütmek için zamanda geriye yolculuk ettiyseniz (belki varsayımsal: )), çıktı aynı zaman olur. Today()sana asla rastgele bir sayı vermez. sana her zaman günün zamanını verir.

Wikipedia makalesi "farklı zamanlar farklı sonuçlar doğuracak" diyor ama bu farklılar x sin(x)için size farklı oranlar verecek. Ve sin(x)onların saf bir fonksiyon örneğidir.


8
Gün içinde geçtiyseniz, işlev ne yapardı?
JB King,

1
Sana günün zamanını vermesini bekliyorum. (en kullanışlı işlev değil). Ancak cevabın kökeni olduğunu düşünüyorum herhangi bir argüman yok.
Brad

3
Çıktısını tahmin edebiliyor musunuz (girdiğiniz giriş parametrelerine dayanarak)?
Daniel B

1
@DanielB Çıktığı yok / boş giriş parametresine hiçbir tahmin gücü yoktur. Yapabileceğim tek şey kol saatime bakmak (cep telefonumdan jk).
Brad

“Neden günün gerçek zamanı“ fonksiyonuna girdi ”” olarak işlem görmedi? Bu, temelde, monadlerin çözmeye çalıştığı sorun. Saf fonksiyonlar sadece girdilerine dayanabilir ve yan etkileri yoktur. Eğer geri dönüş değerinin bir kısmını “benden önce dünya devleti” ve “benden sonra dünya devleti” bir giriş yaparsanız ve bu dünya devletlerini programınızdan geçirirseniz, bir kez daha saf olabilirsiniz.
Sean McSey'de

Yanıtlar:


103

Resmi bir giriş argümanı olmadığı için mi?

Bunun nedeni, çıktının giriş olmayan bir şeye, yani şimdiki zamana bağlı olmasıdır.

Neden günün gerçek zamanı "işleve giriş" olarak değerlendirilmez?

Çünkü parametre olarak geçmediniz. Parametre olarak girmiş olsaydınız, işlev tarihlerde oldukça işe yaramaz bir kimlik işlevi haline gelirdi. Bir Today()işlevin tamamı, harici ve sürekli değişen bir değere (zamana) bağlı bir şey üretmektir.

Saf fonksiyonların avantajı, davranışlarının kesinlikle tekrarlanabilir ve deterministik olması, resmi kanıtlara ve zor garantilere sahip olmayı kolaylaştırmasıdır. Her zaman aynı şeyi yaparlar. Today()hemen hemen tam tersi: her zaman (zaman hassaslığına izin veren) farklı bir şey yapar.


2
Dolayısıyla, gerçekliğin zamanı bir tür girdi olsa bile , bu bir girdi olarak verilmez ve işlevin kontrolü dışında olduğu için (hem işleve hem iç işlev görene, hem de kimin çağırdığını denetleme dışında Today()) Today()zararsız hale gelir. Today()Fonksiyon aptal bir örnek biraz olabilir. Daha uygun bir Count()işlev olabilir . Sayılacak aynı sayıda madde verildiğinde, Count()her zaman aynı sayıyı döndürür, ancak bunun kapsamı dışında olduğu için Count()kesin değildir.
Brad

1
@brad biraz gri bir alana sahip - örtük bir gerçek argüman var - dizi veya liste. Değişmez bir liste ve her defasında aynı argüman verildiğinde her zaman aynı değeri döndürür.
Max

34
“gerçekliğin zamanı bir tür girdi” - evet; Gerçekten de, küresel devlet tüm işlevler için dolaylı olarak kullanılabilir (yani 'bir tür girdi'), ancak sonuçlarına bağlılarsa saf değildir!
AakashM

4
@Brad count(), programlama dillerinin çoğunda kesinlikle saftır. Açık bir giriş değeri vardır: sayısını istediğiniz koleksiyon. Şunun gibi bir sözdizimi ile karıştırmayın myCollection.count(); bu sadece şeker count(myCollection).
Andres F.

Her zamanki gibi büyük cevap, ama açıkça değişmez serbest değişkenleri kapsamaz. İşlev için bir girdi değildir - parametre olarak geçilmez - ancak yine de saydam olsa bile işlev onlara bağlıdır.

24

sin(x)aynı xkaldığı sürece daima aynı değeri döndürür . Today()zamanla farklı sonuçlar verebilir, çünkü kontrolünüz dışındaki değerlere bağlıdır . Örneğin, programın kontrolü dışında bir şey sisteminin iç değiştirirse $current_datetime ise program çalışırken, Today()aniden farklı sonuçlar verecektir.


"her zaman farklı bir değer döndürür" biraz ... saf olmayan ifadelerdir. Wikipedia, "haftanın geçerli gününü döndürüyor" diyor, Pazartesi günleri elde edilen değerlerin değişmeyeceği anlamına geliyor
gnat

7
@gnat: Doğru, programınızın dışında bir şey bilgisayarınızın dahili takvimini değiştirmediyse, aniden Perşembe olduğunu düşünmesi için. Sonra görüşme Today()Pazartesi günü "Perşembe" dönecekti.
SinirliFormsDesigner'la

3
@gnat Her zaman farklı bir değer döndürmez (bunu yapan pek kullanışlı bir işlev yoktur). Ancak, çoğu saf olmayan işlev gibi, dönüş değeri tek bir programın yürütülmesi sırasında bile değişebilir (örneğin, bir gecede çalışıyorsa).

3
@delnan: Evet, bu naif veritabanı senaryo yazarlarının eseri! : P "Ama NASIL 300 kayıtları kaçırabilir? Dün sabah sınava girdiğimde senaryo iyi çalıştı!"
SinirliFormsDesigner'la

@delnan bu kesin. Ben sadece her zaman ilk ifadelerde kullanmanın (şu anki sürüm cevaplarında düzeltilebilecek) düzeltmenin biraz kesin olmadığını belirtmiştim
gnat

13

Today () saf olmayan bir işlevdir, çünkü sonucu size vermediğiniz bir şeye bağlıdır; Özellikle, geçerli sistem zamanı. Bu nedenle, sonuçları yalnızca başvuru sırasında sağlanan girdilere dayanarak belirleyici değildir.

Saf bir işlev olacaktır int Add(int a, int b) {return a + b;}. İşlev yalnızca verilenle çalışır ve başka hiçbir harici durum verisi kullanmaz. Bunun doğal sonucu Add(2,2)şu an 4'ünü zamanın sonuna kadar alabilirsin. Ek olarak, işlev herhangi bir dış durumu değiştirmediğinden ("yan etkisi" yoktur), sizden sonra 2 ve 2'yi ekleyiniz (zamanın sonuna kadar) işlevin sonucunu bir değişkene atayın ya da durumu güncellemek için değeri kullanın (bu işlev tarafından gerçekleştirilen bir işlem değildir). Neredeyse tüm klasik matematiksel işlemler saf fonksiyonlardır ve bu şekilde uygulanabilir.

Bugün (), diğer taraftan, olabilecek birkaç gün arka arkaya denilen eğer bir satırda iki kez aradım, ama aynı değeri vermektedir. Bunun sebebi, fonksiyonun bir parametresi olarak sizin tarafınızdan verilmeyen harici durum verilerine bağlı olmasıdır. Sonuç olarak, programın sınırları dahilinde, Today () işlevinin sonucunu kontrol etmek mümkün değildir. Belirli bir günde belirli bir değer üretecek ve üzerinde çalıştığı bilgisayarın sistem saatini değiştirmediğiniz sürece (genellikle programın sınırları dışında gerçekleşen bir değişiklik olmadıkça) bu değeri başka hiçbir günde üretmeyecektir.

Saf olmayan bir fonksiyon mutlaka kötü bir şey değildir; Fonksiyonel dillerde bile, veri depoları, iletişim boru hatları, kullanıcı arayüzü ekranları, çevresel aygıtlar vb. gibi program sınırları dışındaki herhangi bir şeyle etkileşime girmek için impure işlevlerine ihtiyaç duyulur. Bunlardan hiçbirini yapmayan bir program bu, kullanımında keskin bir şekilde sınırlıdır; Böyle bir programın önemsiz olduğunu söyleyeceğim bir yere bile gideceğim, çünkü girdiyi ya da çıktısını size bildirecek herhangi bir yolu kabul etmeden hiçbir şey yapmıyor olabilir. İşlevsel dillerde yazılmış programlar, yalnızca çalışma zamanı tarafından sağlanan girdiye sahip olabilir ve açıkça tanımlanmış herhangi bir kesin olmayan yöntem olmadan çalışma zamanına bildirilen bir çıktı üretebilir, ancak çalışma zamanının kusurlu bir bilgisayar sistemi içinde çalışmanın tüm bu saf olmayan ayrıntılarını kaldırması nedeniyle,

Kullanmakta olduğunuz işlevlerin hangilerinin saf olduğunu ve hangilerinin olmadıklarını bilmek çok iyi bir şeydir, bu yüzden nasıl kullanıldığı konusunda iyi kararlar verebilirsiniz. Saf olmayan işlevler, bir şeyleri yaptıkları veya kullanımlarından açıkça görülmeyen şeylere bağımlı oldukları için, yalnızca kullanım bilgisi dikkate alındığında tahmin edilemez şekilde davranabilir. İşlevin amacını ve dolayısıyla dış devletten ne gerektirdiğini veya dışsal bir yapıya ihtiyacı olan daha fazla bilgi, onu tutarlı bir durumda kullanan bir sistemi yerleştirmek ve böylece belirleyici bir sonuç beklemek için gereklidir.


8

Bu fonksiyonun, bu sayfanın başında verilen ilk saflık testini geçememesi oldukça açık görünüyor:

  1. İşlev her zaman aynı argüman değerleri verilen aynı sonuç değerini değerlendirir. İşlev sonucu değeri, program yürütme ilerledikçe veya programın farklı yürütmeleri arasında değişebilecek hiçbir gizli bilgiye veya duruma ya da G / Ç aygıtlarından herhangi bir harici girişe bağlı olamaz.

Hiçbir argüman almadığından, yalnızca bir olası argüman değeri kümesi olduğunu unutmayın - boş küme. Ve bu işlev aynı 'argüman değerleri / değerleri için farklı sonuçlar verebilir ve döndürür .

Dahası, fonksiyon sonucu değeri yok "programı yürütme ilerledikçe değişebilir gizli ... devlet" bağlıdır. Yani başka bir başarısızlık.


@ JörgWMittag Argüman içermeyen bir işlevin değer döndüremediğini iddia ettiğimden emin değilim.
AakashM

Beyin osuruğu. "Sadece bir tane geri dönüş değeri kümesi var" yazdım .
Jörg W Mittag

8

() => 1her zaman 1 döndürdüğü için saf bir işlev olacaktır, Today()"Pazartesi" veya "Salı" veya hemen hemen başka bir değer verebilir.

Bunu düşünmenin bir başka yolu da saf fonksiyonlar duruma bağlı değildir. Dünya genellikle devlet olarak kabul edilir. Bugünün hangi gün olduğunu bilmek için gerçeğin durumunu bilmek gerekir.

Ancak ne sin(x)olduğunu bilmek için dünyanın durumu hakkında özel bir şey bilmenize gerek yok . Ve şimdiye kadar sin(x)verilen bir çağrı için xaynı değeri verir.


Vikipedi o "1/24/2013" Pazartesi, Salı vb dönmek değil "1/23/2013" ne, yani "döner haftanın Geçerli gün" diyor
tatarcık

7
@gnat: Güncelleme yapıldı, ancak fark gerçekten önemli değildi.
Guvante

2

Date(timestamp)saf bir işlev olurdu. İfadesi nedeniyle. Ve çünkü hiçbir yan etki olmaz.

Today()ne zaman aradığınıza bağlı olarak sonucunu değiştirebilir . Onu saflaştıran şey budur. Idempotent değil. Yine de hiçbir yan etkisi yoktur, fakat bu onu saflaştırmaz.


2

İşte saf fonksiyonları tartışırken aklıma gelen küçük bir kod

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Eğer bu süresiz çalışırsa ve asla assert'i tetikleyemezse, saf bir fonksiyondur. Daha fazla, args kullanan bir işlev varsa, o zaman küçük bir değişiklik ....

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Uygulamanızdaki her değişken atamasından sonra bunu kullanabilirseniz ve uygulamanızdaki sonuçları değiştirmezse ve iddiada asla başarısız olmazsa, o zaman saf bir işlevdir.


2

İlk olarak, argümansız bir fonksiyon (veya indeks içermeyen bir dizi veya anahtarsız bir harita) diye bir şey yoktur. Bir veya daha fazla argüman değerini başka bir değerle eşlemek, işlevin tanımlayıcı özelliğidir.

Dolayısıyla, todayya hiç bir işlev değil, dolayısıyla hiçbir saf işlev değildir. Veya sözdizimini yorumlayabiliriz.

today()

biraz demek ki

today   ()      -- today, applied to the value ()

Haskell'de, örneğin, bu geçerli olur:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

çünkü tek bir değere () sahip bir tip () var.

Sorun yalnızca, todayeğer varsa () haftanın gününü nasıl hesaplayabilir? Sistem zamanlayıcısını okumadan, doğrudan veya yardımcı impuls fonksiyonlarıyla mümkün değildir.

Sistem zamanlayıcısı, küresel durum için mükemmel bir örnektir.


1

Sorun today(), bir işlevde iki veya daha fazla kez çağrıldığında farklı bir sonuç vermesidir.

İşte bir hataya yol açabilecek bir kod örneği.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

Yukarıdaki örnekte mümkündür. İkinci ififadenin yürütülmeyeceği. Birincisi olsa bile. Bir kaynağı kötü durumda bırakmak.


1

Saf bir fonksiyon olması için, aynı parametreleri sağlamak her zaman aynı sonucu vermelidir.

Her aradığımız zaman Today(), aynı parametreleri sağlıyoruz (hiçbiri) ve yine de aynı sonucu almıyoruz (Pazartesi, Salı vb.).


4
Bu, sadece iki yıl önce yayınlanan en iyi yanıtta yapılan ve açıklanan noktayı tekrarlamak gibi görünüyor . Bunun gibi içeriğe sahip iki yıllık bir soruyu çarpmaya değmez
gnat

1
Stackexchange'in nasıl çalıştığına çok aşina değilim, ancak bunun çoktan çarpıldığına dair en önemli sorulardan biri olduğunu düşündüm. Tekrarlama noktası geldiğinde, meta üzerinde okuduğumu, benzer cevapların birden fazla olmasının faydalı olabileceğini hatırlıyorum. Benimkinin özlü ve potansiyel olarak yardımcı olduğunu hissediyorum.
Zantier,
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.