Bir işlev parametre olarak bir işlev gerektiriyorsa derhal kirletilebilir mi?


17

Bir giriş parametresinin saflığı, çalışma zamanına kadar bilinmediği için, bir işlev bir giriş parametresi olarak işlev görürse hemen saf olmayan bir işlem olarak kabul edilir mi?

İlgili: Bir işlev, işlevin dışında tanımlanan ancak parametre olarak iletilmeyen saf bir işlev uygularsa, yan etkisi olmayan ölçütleri yerine getiriyorsa ve çıktı yalnızca girdiye bağlıysa hala saf mıdır?

Bağlam için, JavaScript'te işlevsel kod yazıyorum.


Önemsiz bir karşı örnek olarak düşünün:foo = function(function bar){ print(bar.toString()) }
David diyor Reinstate Monica

1
@DavidGrinberg Bence bu karşı bir örnek değil ve aslında daha büyük bir sorunu vurgular; geçersiz kılınabilecek işlevleriniz varsa ve uygulamaların yan etkisiz olduğunu garanti edemiyorsanız, nesne alan ve yöntemlerini çağıran işlevlerin çoğunun da saf olduğunu garanti edemezsiniz. Belki çubuğun toString () bazı dosyaları diskten siler?
Joshua Taylor

3
@DavidGrinberg Ama bence iyi bir yönde düşünüyorsun. foo = function(function bar) { return 3; } olan , saf, bir argüman olarak bir işlev alır.
Joshua Taylor

@JoshuaTaylor Fair point, bunu düşünmedim. Ama sorunu zaten çözdün. Alternatif bir düzeltme olarak, sadece 'kök' toString()(yani Java'nın Nesnesinde bulacağınız) deyin .
David, Reinstate Monica'ya

Yanıtlar:


22

İşlevde kullanılan tüm değerler yalnızca parametreleri tarafından tanımlandığı sürece, saf bir işlevdir.

Aynı girdi için her seferinde çıkışın aynısı parametrelerin saf olup olmadığı kontrol edilir. Parametrelerin (işlev argümanı gibi) de saf olduğunu varsayarsanız, o zaman saf olur.

Saflığın uygulanmadığı Javascript gibi bir dilde, bu, başka türlü saf bir işlevin, parametre olarak geçirilen bir safsızlık işlevini çağırarak saf olmayan davranışa sahip olmasını mümkün kıldığı anlamına gelir.

Bu etkili bir şekilde, saflığı zorlamayan diller için (yani neredeyse hepsi), argümanlar olarak geçirilen işlevleri çağıran saf bir işlevi tanımlamanın imkansız olduğu anlamına gelir. Bunları olabildiğince saf yazmak ve onlar hakkında saf işlevler olarak düşünmek hala yararlıdır, ancak dikkatli olmanız gerekir, çünkü yanlış argümanları iletirseniz saf olduğu varsayımı kırılacaktır.

Uygulamadaki tecrübelerime göre, bu genellikle büyük bir sorun değildir - saf olmayan işlevlerin saf işlevlere işlev argümanları olarak kullanılmasının nadir olduğunu düşünüyorum.


"İşlevde kullanılan tüm değerler yalnızca parametreleri tarafından tanımlandığı sürece, bu saf bir işlevdir" ifadesine göre. Sabitler durumunda ne olur? Eğer bir fonksiyonum varsa areaOfCircle r => Math.Pi * r * r, areaOfCirclesadece parametreleri kullanmakla kalmayıp saf değil mi?
David Arno

2
@DavidArno Bu adil bir nokta. Referans şeffaflığına göre, statik bir dış değere atıfta bulunmak , onu kodlamaktan farklı olmayacaktır, bu yüzden yine de saf olacaktır.
Daenyth

1
"Bu, saf bir fonksiyonun saf olmayan davranışa sahip olmasını mümkün kıldığı anlamına gelir" - tanım gereği, saf bir fonksiyonun saf olmayan davranışları olamaz. f(f2)Çağıran bir işlevi düşünmeye f2dayanan bir şeye geçici olarak bağlı olmayan bir düşünme düşüncesinde hata yapıyorsunuz f2. Rasgele aktarılan işlevleri çağırabilecek bir işlev saf değildir.
user2357112 Monica

2
@Daenyth: Daha iyi, ama yine de işlevin geçilen işlevi çağırması gerektiğini varsayar. function compose(f, g) {return function h(x) {return f(g(x));};}Fonksiyonları argüman olarak almasına rağmen saf olan bir şey olabilir .
user2357112 Monica

1
"Saf olmayan işlevlerin saf işlevlere işlev argümanları olarak kullanılmasını nadir görüyorum." - işlevsel bir dil değil, ancak bazı C ++ kütüphane işlevlerinde yüklem argümanlarının saf olması gereken bazı uyarılar vardır. Yani bir anlamda bu sadece nadir olmakla kalmaz, asla geçerli olmaz. Ama başka bir anlamda, bunu yasaklamak zorunda olmaları gerçeği, insanların bazen yapmak istedikleri için. Örneğin find, karşılaştıkları üçüncü eşleme öğesi veya "bu saçmalık" için "doğru" döndüren saf olmayan bir yüklemi rutin olarak iletmek isterler .
Steve Jessop

19

Bir giriş parametresinin saflığı, çalışma zamanına kadar bilinmediği için, bir işlev bir giriş parametresi olarak işlev görürse hemen saf olmayan bir işlem olarak kabul edilir mi?

Hayır. Karşı örnek:

function pure(other_function) {
    return 1;
}

other_functionSaf bir işlev, saf olmayan bir işlev olup olmadığı önemli değildir. pureİşlev saftır.

Diğer karşı örnek:

function identity(x) {
    return x;
}

Bu işlev saf xolmayan bir işlev olsa bile saftır . aramayı kaç kez tekrarlarsanız yapın identity(impure_function)daima geri dönecektir impure_function. Her identity(impure_function)()zaman aynı şeyi döndürüp döndürmeyeceği önemli değildir ; bir işlevin dönüş değerinin dönüş değeri saflığını etkilemez.


Genel olarak, bir işlev bağımsız değişken olarak geçirilmiş bir işlevi çağırabiliyorsa, saf değildir. Örneğin, bir işlev function call(f) {f();}saf değildir, çünkü herhangi bir küresel veya değişebilir durumdan bahsetmese de, görünür yan etkilere neden olan bir fşey olabilir alert.

Bir işlev işlevleri bağımsız değişken olarak alır, ancak bunları çağırmaz veya çağrılmasına neden olmazsa, saf olabilir. Başka bir saf olmayan şey yaparsa yine de saf olmayabilir. Örneğin, function f(ignored_function) {alert('This isn't pure.');}asla çağırmasa bile saf değildir ignored_function.


4
Bu yanıt aşırı derecede bilgiç görünüyor. Endişenin çağrılan fonksiyon parametresi üzerinde olduğu sorusundan çıkarımda bulunabiliriz. Diğer işlevleri çağırmadan parametre olarak alabilen / yapabilecek işlevlerin varlığı bu soruyu etkilemez.
Walpen

13
@walpen: Soru, tartışmayı başlattığından bahsetmiyor. Sorgunun, bir fonksiyonun başka bir fonksiyonu çağırmadan girdi olarak alabileceğini bile fark etmesinin bir nedeni yoktur. Bu tür gizli varsayımlara işaret etmek önemlidir, sadece bunları varsaymayı düşündüğünüzü varsaymak yerine.
user2357112 Monica

12

Bir giriş parametresinin saflığı, çalışma zamanına kadar bilinmediği için, bir işlev bir giriş parametresi olarak işlev görürse hemen saf olmayan bir işlem olarak kabul edilir mi?

Teknik olarak, evet, dilinizde giriş işlevinin de saf olduğunu garanti etmenin bir yolu yoksa.

Bir işlev, işlev dışında tanımlanan ancak parametre olarak iletilmeyen saf bir işlev uygularsa, yan etkisi olmayan ölçütleri yerine getiriyorsa ve çıktı yalnızca girdiye bağlıysa hala saf mıdır?

Evet. Öyleyse burada önemli olan şeylere odaklanalım. Bir işlevi saf olarak adlandırmak ya da çağırmak kendi başına yararlı değildir. Saf işlevler yararlıdır, çünkü herhangi bir giriş için aynı çıktıyı üretmek ve duruma bağlı olmamak veya yan etkilere sahip olmak çok yararlı bir özellik kümesidir. Bu, fonksiyonunuz çalıştırıldıktan sonra, bu girişin cevabını "hatırlayabileceğiniz" anlamına gelir ve her zaman doğru olacaktır. Ayrıca, yan etkiler oluşturmak için işlevi tekrar çalıştırmanız gerekmez. Ve bu işlevi diğer işlevlerle paralel (ya da arızalı) olarak çalıştırabilir ve kötü davranan herhangi bir gizli etkileşime sahip olmayacaklarını bilirsiniz.

Bu faydalı özellikler, işlev, çalışmalarını yapmak için başka saf salt okunur işlevler kullanıyorsa, bunlara nasıl başvurduğundan bağımsız olarak kalır.


5

Telastyn'in dediği gibi: Teknik olarak, evet, giriş işlevinin de saf olduğunu garanti etmenin bir yolu yoksa.

Bu varsayımsal değil, bunu garanti etmenin gerçekten iyi yolları var. En azından kuvvetle yazılmış bir dilde.

JavaScript'te yazacağınız gibi saf bir işlev

function foo(f) {
   return f(1) + 2;
}

doğrudan Haskell'e çevrilebilir:

foo :: (Int -> Int) -> Int
foo f = f 1 + 2

Şimdi JavaScript'te kötü şeyler yapabilirsiniz

js> foo (function(x) {console.log("muharhar"); return 0})
muharhar
2

Haskell'de bu mümkün değil . Nedeni, yan etki gibi console.log()bir IO somethingşey sadece somethingyalnız değil, her zaman bir sonuç türüne sahip olmalıdır .

GHCi> foo (\x -> print "muarhar" >> return 0)

<interactive>:7:12:
    Couldn't match expected type ‘Int’ with actual type ‘IO b0’
    In the expression: print "muarhar" >> return 0
    In the first argument of ‘foo’, namely
      ‘(\ x -> print "muarhar" >> return 0)’
    In the expression: foo (\ x -> print "muarhar" >> return 0)

Bu ifadenin daktiloyu kontrol etmesi fooiçin tür imzası vermemiz gerekir

foo :: (Int -> IO Int) -> Int

Ama o zaman artık uygulayamadığım ortaya çıkıyor: çünkü argüman işlevi IOsonuçta olduğu için onu kullanamıyorum foo.

<interactive>:8:44:
    Couldn't match expected type ‘Int’ with actual type ‘IO Int’
    In the first argument of ‘(+)’, namely ‘f 1’
    In the expression: f 1 + 2

Bir IOeylem kullanabilmenin tek yolu foosonucu footür IO Intkendisi ise:

foo :: (Int -> IO Int) -> IO Int
foo f = do
   f1 <- f 1
   return (f1 + 2)

Ancak bu noktada foo, bunun saf bir işlev olmadığı imzasından da anlaşılmaktadır .


1
"İmkansız" demeden önce unsafeIO:-)
Bergi

2
@Bergi: bu aslında Haskell'in değil, yabancı işlev arayüzünün bir parçası: başka bir dilde tanımlanan bir fonksiyonun saf olduğunu iddia etmek için , Haskell derleyicisinin açıkça tür imzasından çıkamadığından, diğer diller genellikle yok gibi bir şey IO. Bu arada, “saf” bir fonksiyonda yan etkileri gizleyerek kargaşaya neden olmak için de kullanılabilir, ancak Haskell'de bu gerçekten güvensizdir, çünkü saf fonksiyonların değerlendirme sırasını belirtmek için gerçekten güvenilir bir yol yoktur.
leftaroundabout

Evet doğru. Ancak, yaklaşımın güvenliğinin daha önce belirlenmesi gereken bir "saf" işlevde de yararlı yan etkileri "gizlemek" için kullanıldığını düşünüyorum .
Bergi

@Bergi Çoğunlukla kullanmamalısınız unsafeIO; bu, tip sisteminin garantisini veren son çare kaçış kapağıdır ve bu nedenle sizinki iyi bir nokta değildir.
Andres

0

Hayır öyle değil.

Geçilen işlev saf değilse VE işleviniz geçirilen işlevi çağırırsa, işleviniz saf olmayan olarak değerlendirilir.

Saf / impure ilişkisi JS'deki senkron / async'e benzer. Saf kodu saf olmayan bir şekilde özgürce kullanabilirsiniz, ancak tam tersi şekilde kullanamazsınız.


Bu cevap, bu konuda henüz açıklanmayan hiçbir şey eklemiyor ... Lütfen şeyleri yeniden düzenlemeden önce önceki yanıtları gözden geçirin :)
Andres F.

Senkronizasyon / zaman uyumsuzluk benzetmesi ne olacak?
Bobby Marinoff
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.