Bir işlev safsa hesapla


11

Wikipedia'ya göre:

Bilgisayar programlamasında, işlev tutma ile ilgili bu ifadelerin her ikisi de bir işlev olarak tanımlanabilir: İşlev, aynı bağımsız değişken değerleri verildiğinde her zaman aynı sonuç değerini değerlendirir. İşlev sonuç 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 veya G / Ç aygıtlarından gelen herhangi bir harici girdiye bağlı olamaz. Sonucun değerlendirilmesi, değiştirilebilir nesnelerin mutasyonu veya G / Ç cihazlarına çıktı gibi herhangi bir anlamsal olarak gözlenebilir yan etkiye veya çıktıya neden olmaz.

Bir fonksiyonun saf olup olmadığını hesaplayan bir fonksiyon yazmanın mümkün olup olmadığını merak ediyorum. Javascript'teki örnek kod:

function sum(a,b) {
    return a+b;
}

function say(x){
    console.log(x);
}

isPure(sum) // True
isPure(say) // False

7
Bu Bilgisayar Bilimi Yığın Değişimi için aday olabilir . Bu, pratik ve tasarımdan ziyade teori alanına ("mümkün") daha fazla eğilimlidir ... Ken'imin biraz ötesinde.

... ve "mümkün" ve "teori" olmasına rağmen, bir kanıt bile içerebilecek gerçek bir cevap (Soru-Cevap için iyi bir uyum) olabilir ... ki bu da onu tekrar bilgisayar bilimi dünyasına geri götürür .

Bir fonksiyonun saf olup olmadığını, tanımında çağrılan fonksiyonların türüne bakarak belirleyebileceğinizi düşünüyorum. Demek istediğim, saflığı fonksiyonların yapısına indükleyerek tanımlayabilirsiniz.
Giorgio

7
Platforma özel yansıma korsanları olmadan yapmak mümkün değildir. Bir işlev bir kara kutu ise, hiçbir deney saf olduğunu ispatlayamaz . Örneğin, böyle bir şey varsa if (rand(1000000)<2) return WRONG_ANSWER, tutarlı bir davranış için işlevi birçok kez araştırmak yardımcı olmaz. Ancak, işlev tanımına erişiminiz varsa, kanıt önemsizdir.
SK-logic

1
@ user470365 Saf bir işlevin tanımından - "Sonucun değerlendirilmesi, değiştirilebilir nesnelerin mutasyonu veya G / Ç aygıtlarına çıktı gibi semantik olarak gözlemlenebilir yan etkilere veya çıktılara neden olmaz." - ES'ye yazan her şey tanım gereği saf değildir. Örnekte , saf olmayan sayçağrılar console.logda saysaf değildir.

Yanıtlar:


17

Evet, dile bağlı olarak mümkündür.

JavaScript'te, bir işlevin saf olup olmadığını aşağıdaki ölçütlere göre anlayabilirsiniz:

  • Yalnızca parametreleri ve yerel ayarları okur;

  • Sadece yerliler yazar;

  • Yerel olmayanlarda, yalnızca saf işlevler çağırır;

  • Örtük olarak çağırdığı tüm işlevler saftır toString; ve

  • Yerel olmayanların özelliklerini yalnızca yerel olmayanların diğer adını takma adlarıyla yazmazlar.

Genelde JavaScript'te takma ad belirlemek mümkün değildir, çünkü bir nesnenin özelliklerini her zaman dinamik olarak arayabilirsiniz ( object["property"]). Bunu asla yapmamanız ve tüm programın kaynağına sahip olmanız şartıyla, sorunun izlenebilir olduğunu düşünüyorum. Ayrıca, hangi yerel işlevlerin console.log, DOM ile ilgili veya bunun gibi herhangi bir yan etkisi olduğu hakkında bilgi gerekir .

“Saf” terimi de bazı açıklamaları kullanabilir. Tüm işlevlerin referans olarak saydam olduğu, güçlü, statik olarak yazılmış, tamamen işlevsel bir programlama dilinde bile, bir işlev hala sonlanamayabilir. Yani hakkında konuştuğumuzda id :: a -> a, gerçekten söylediğimiz şey:

Bir tür değer verildiğinde a, işlev idbir tür değeri üretir a.

Daha ziyade:

Tip bazı değerini göz önüne alındığında a, fonksiyon idyok değil bir değer üretmek değil Çeşidi a.

Geçerli bir uygulamaya Çünkü idDİR error "Not implemented!". Peteris'in belirttiği gibi, bu toplamsızlık bir tür safsızlık olarak görülebilir. Koka , ayrışma (sonlandırma), referans şeffaflığı, istisnalar atma ve G / Ç eylemleri gibi olası etkileri ortaya çıkarabilen işlevsel bir programlama dilidir (JavaScript üzerinde modellenmiş sözdizimi ile).


+1 - Peteris tarafından verilen yanıt, bu kadar çok oy aldı .....
mattnz

Ölçüt listesine "Sadece saf işlevleri çağırıyor" eklemeniz gerektiğini düşünüyorum.
Greg Hewgill

1
@GregHewgill: İyi yakaladın. Cevabı buna göre güncelledim. Başka bir şekilde yan etkili olmadıkları sürece, yerliler üzerinde mutasyon işlevlerini çağırmak iyidir . “Saf” bir terime aşırı yüklenmiş…
Jon Purdy

Ayrıca toString, dize olarak kullandığınız herhangi bir nesne için saf olup olmadığını da kontrol etmeniz gerekir .
Oleg V.Volkov

Bu cevabın doğru olduğunu düşünmüyorum, çünkü bu saptamaları gerçekten yapabileceğiniz koşulların sadece bir alt kümesi var. Şunu düşünün: Bu işlev saf mı? function a (o) { return o.method(); }- buna gerçekten cevap veremeyiz, çünkü hangi parametrenin ogeçtiğine bağlıdır . Ayrıca, önceden onaylanmış saf bir işlev saf olmayan bir uygulamaya dönüştürülürse ne olacağını açıklayamayız, bu da her zaman javascript ile ilgili potansiyel bir sorundur.
Jules

11

Hayır. Bir fonksiyonun Jon Purdy'nin cevabında açıklandığı gibi sadece "saf-güvenli" işlemler yapıp yapmadığını kolayca kontrol edebilirsiniz, ancak IMO bu soruya cevap vermek için yeterli değildir.

Bu işlevi göz önünde bulundurun:

function possiblyPure(x) {
    if (someCheck(x)) {
        return x+1; // pure code path
    }
    else {
        console.log("I'm so unpure..."); // unpure code path
    }
}

Açıkçası, eğer someChecksaf değilse de öyle possiblyPure. Ama, eğer someChecksaf ve iadeler trueolası her değeri için x, possiblyPureunpure kod yolu ulaşılamaz olduğundan, saftır!

Ve işte zor kısım geliyor: someCheckolası her giriş için doğru döndürülüp döndürülmeyeceğini belirlemek . Bu soruyu hemen cevaplamaya çalışmak sizi durdurma problemine ve benzeri kararsız sorunlara götürür.

EDIT: imkansız olduğunu kanıtlamak

Saf bir işlevin olası her girdide sonlanması gerekip gerekmediği konusunda bazı belirsizlikler vardır. Ancak her iki durumda da, durma problemi, saflık kontrolünün imkansız olduğunu göstermek için kullanılabilir.

Durum A) Olası her girişte sonlandırmak için saf bir işlev gerekiyorsa , işlevin saf olup olmadığını belirlemek için durma sorununu çözmeniz gerekir . Bunun imkansız olduğu bilindiğinden, bu tanım ile saflık hesaplanamaz.

Durum B) Saf bir işlevin bazı girdilerde sonlanmasına izin verilmiyorsa, şöyle bir şey oluşturabiliriz: Saf bir işlevi tanımlayan bir dize isPure(f)olup olmadığını hesaplayalım f.

function halts(f) {
   var fescaped = f.replace(/\"/g, '\\"');
   var upf = 'function() { '+f+'("'+fescaped+'\); console.log("unpure"); }';
   return isPure(upf);
}

Şimdi girdi olarak kendi kaynağında durup durmadığını isPurebelirlemelidir f. Durursa, upfsaf değildir; eğer upfbitmezse saf mıdır saf mıdır f.

Eğer isPurebeklenen (her girişinde döner doğru sonuçlar ve sonlandığı) olarak çalıştı, biz durdurulması problemi (*) çözülmüş olurdu! Bunun imkansız olduğu bilindiğinden, var isPureolamaz.

(*), turing makinesi için de çözmek için yeterli olan saf JavaScript işlevleri için.


3
Doğru. Konservatif bir analiz yapmak her zaman mümkündür - bir fonksiyonun kesinlikle saf olup olmadığını kontrol etmek, ancak kesinlikle saf olup olmadığını kontrol etmek mümkün değildir.
SK-logic

Birçok vaka önemsizce karar verilebilir - Jon Purdy tarafından tanımlanan saf işlevler veya koşulsuz olarak kirli bir şey yapan saf olmayan işlevler; ancak genel olarak, karar verilemeyen vakalar inşa edilebilir.
user281377

1

Bu yığın akışı sorusunun yfeldblum tarafından burada alakalı bir yanıtı vardır. (Ve bazı nedenlerden ötürü aşağılamam var. Kulağa kavuşamıyorum. 3 yaşında bir şeyi düzeltmek kötü görgü kuralları mı olur?) Bir fonksiyonun saf olup olmadığını bir yorumdaki durma problemine indirgenebilir olduğuna dair bir kanıt verir.

Pratik açıdan bakıldığında, işlevin evet, hayır veya belki geri dönmesine izin verirseniz bazı diller için çok zor olmaz. Birkaç gün önce Clojure hakkında bir video izliyordum ve konuşmacı yaklaşık 4 farklı dizeyi ("ref" gibi) arayarak bir kod tabanında safsızlık örnekleri yapmıştı. Clojure'un saf olmayan şeylerin saflığına ve ayrışmasına verdiği önem nedeniyle, önemsizdi, ancak tam olarak aradığınız şey değildi.

Yani, teorik olarak imkansız, eğer soruyu biraz değiştirirseniz pratik olarak mümkün ve bence bunun ne kadar zor olacağını büyük ölçüde dile bağlı olacaktır. Değişmezlik ve iyi yansıma odaklı daha basit / temiz diller daha kolay olurdu.


Tahmin ediyorum, yanlış değerlendirilmişti çünkü yanlış. bottomgeçerli, birinci sınıf bir değerdir, bu şekilde ayrımcılığa uğratılmayı hak etmez.
SK-logic

0

Harika bir soru.

Pratikte yapabileceğiniz en iyi şey, işlevi mümkün olduğu kadar çok kez çağırmak için g / Ç işlemlerini dinleme yeteneği olmadığını varsayar. Ardından, dönüş değerinin tutarlı olup olmadığına bakın.

Ama bunu genel olarak yapamazsınız. Tartışmasız, durmak bilmeyen programlar saf değildir ve durma problemine karar veremeyiz.


1
-1: Bu testi geçen ve saf olan bir işlev yazmak önemsiz bir şey olacaktır.
22:10

3
Bu mantıkla, herhangi bir voidfonksiyon "saf" olacaktır, ki bu açıkça yanlıştır.
Greg Hewgill

1
@Greg: Ek olarak, void foo'nun (void) da saf olması gerekir.
mattnz

0

Genel durumda mümkün değil. Durdurma sorununa bakın . Kısaca, keyfi bir işlev ve girdi verildiğinde, programın sonsuza kadar durup durmayacağını belirleyen bir program yazmak imkansızdır. Sonsuza kadar çalışırsa, verdiğiniz tanıma uyan saf bir işlev değildir .


5
Sonsuza kadar koşmak, bir işlevi saf bir işlev için ölçütlerine uymaktan alıkoyuyor gibi görünmüyor.
whatsisname

+1: Fonksiyonun "işlev her zaman aynı sonuç değerini verir ...." ile sonlandırılması için örtük bir zorunluluk vardır
mattnz

2
Herhangi bir durumu değiştirmeden sürekli olarak sonsuza dek koşmak mükemmel "saf" tır. Ancak, elbette, bu bir terminoloji konusudur.
SK-logic

@mattnz, böyle bir işlev her zaman bottomdeğeri değerlendirir .
SK-logic

1
Terminoloji sorununun nereden geldiğini görebiliyorum. Bazı yorumlarda, "saf" işlev, yürütme sırasında hiçbir durum veya değeri hiçbir zaman dışa iletmemek kadar belirleyici olan bir işlevdir. Diğer yorumlarda, gereksinimlere durma eklenir. İlk yorumla, bir fonksiyonun saf olup olmadığını belirlemek kolaydır: belirli bir dili yürüten bir makine, o dildeki bir programın dış ile herhangi bir iletişim kurup kurmadığını belirleyebilmelidir.
rwong
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.