Yan etkileri olan kapaklar “işlevsel tarz” olarak kabul edilir mi?


9

Birçok modern programlama dili, bazı kapatma kavramlarını , yani bir kod parçasını (blok veya işlev) destekler.

  1. Bir değer olarak değerlendirilebilir ve bu nedenle bir değişkende saklanabilir, kodun farklı bölümlerine aktarılabilir, bir programın bir bölümünde tanımlanabilir ve aynı programın tamamen farklı bir bölümünde çağrılabilir.
  2. Değişkenleri tanımlandığı bağlamdan yakalayabilir ve daha sonra çağrıldığında bunlara erişebilir (muhtemelen tamamen farklı bir bağlamda).

İşte Scala'da yazılmış bir kapanış örneği:

def filterList(xs: List[Int], lowerBound: Int): List[Int] =
  xs.filter(x => x >= lowerBound)

İşlev değişmezi , aynı ada sahip işlevin bağımsız değişkeni tarafından kapatılan (bağlı) olan x => x >= lowerBoundserbest değişkeni içerir . Kapatma, tekrar tekrar normal bir işlev olarak çağırabilen kitaplık yöntemine geçirilir .lowerBoundfilterListfilter

Bu sitede birçok soru ve cevap okuyorum ve anladığım kadarıyla kapatma terimi genellikle otomatik olarak fonksiyonel programlama ve fonksiyonel programlama stiliyle ilişkilendiriliyor.

Wikipedia'da fonksiyon programlamanın tanımı şu şekildedir:

Bilgisayar biliminde fonksiyonel programlama, hesaplamayı matematiksel fonksiyonların değerlendirilmesi olarak ele alan ve durum ve değişken verileri önleyen bir programlama paradigmasıdır. Durumdaki değişiklikleri vurgulayan zorunlu programlama stilinin aksine, fonksiyonların uygulanmasını vurgular.

ve dahası

[...] fonksiyonel kodda, bir fonksiyonun çıkış değeri sadece [...] fonksiyonuna girilen argümanlara bağlıdır. Yan etkilerin ortadan kaldırılması, fonksiyonel programlamanın geliştirilmesi için temel motivasyonlardan biri olan bir programın davranışını anlamayı ve tahmin etmeyi çok daha kolay hale getirebilir.

Öte yandan, programlama dilleri tarafından sağlanan birçok kapatma yapısı, bir kapağın yerel olmayan değişkenleri yakalamasına ve kapatma çağrıldığında bunları değiştirmesine izin verir, böylece tanımlandıkları ortam üzerinde bir yan etki üretir.

Bu durumda, kapaklar işlevsel programlama ilk fikrini uygular (fonksiyonlar diğer değerler gibi hareket edebilen birinci sınıf varlıklardır) ancak ikinci fikri ihmal eder (yan etkilerden kaçınır).

Yan etkileri olan kapakların bu kullanımı fonksiyonel tarz olarak mı kabul edilir, yoksa kapaklar hem işlevsel hem de işlevsel olmayan bir programlama stili için kullanılabilecek daha genel bir yapı mıdır? Bu konuda literatür var mı?

ÖNEMLİ NOT

Yan etkilerin veya yan etkilerle kapanmaların faydasını sorgulamıyorum. Ayrıca, yan etkileri olan veya olmayan kapakların avantajları / dezavantajları hakkında bir tartışma ile ilgilenmiyorum.

Sadece bu tür kapakların kullanılmasının hala fonksiyonel programlamanın savunucusu tarafından işlevsel bir stil olarak kabul edilip edilmediğini veya aksine, fonksiyonel bir stil kullanılırken kullanımlarının engellenip engellenmediğini bilmekle ilgileniyorum.


3
Tamamen işlevsel bir tarzda / dilde, yan etkiler imkansızdır ... bu yüzden bir sorun olacağını tahmin ediyorum: kodun hangi saflıkta işlevsel olduğunu düşünüyoruz?
Steven Evers

@SnOrfus:% 100'de misiniz?
Giorgio

1
Yan etkiler tamamen işlevsel bir dilde imkansızdır, bu yüzden sorunuza cevap vermelidir.
Steven Evers

@SnOrfus: Birçok dilde kapaklar işlevsel bir programlama yapısı olarak kabul edilir, bu yüzden biraz kafam karıştı. Bana öyle geliyor ki (1) kullanımları sadece FP yapmaktan daha geneldir ve (2) kapanışları kullanmak kişinin işlevsel bir stil kullandığını otomatik olarak garanti etmez.
Giorgio

Düşürücü bu sorunun nasıl geliştirileceğine dair bir not bırakabilir mi?
Giorgio

Yanıtlar:


7

Hayır; işlevsel paradigmanın tanımı, devletin olmaması ve dolaylı olarak yan etkilerin olmaması ile ilgilidir. Üst düzey işlevler, kapaklar, dil destekli liste manipülasyonu veya diğer dil özellikleri ile ilgili değildir ...

Fonksiyonel programlamanın adı, fonksiyonların matematiksel kavramından gelir - aynı girişte tekrarlanan çağrılar her zaman aynı çıkış nullipotent fonksiyonunu verir. Bu ancak veriler değiştirilemezse elde edilebilir . Gelişimi kolaylaştırmak için, işlevler değişebilir hale geldi (işlevler değişiyor, veriler hala değişmez) ve böylece daha üst düzey işlevler kavramı ( örneğin, türevler olarak matematikteki işlevler) - başka bir işlevi girdi olarak alan bir işlev. Fonksiyonların argüman olarak taşınması ve aktarılması olasılığı için birinci sınıf fonksiyonlar benimsenmiştir; bunları takiben verimliliği daha da artırmak için kapaklar ortaya çıktı.

Bu elbette çok basitleştirilmiş bir görüştür.


3
Üst düzey işlevlerin kesinlikle değiştirilemezlik ile hiçbir ilgisi yoktur, birinci sınıf işlevler de yoktur. Haskell'de herhangi bir değişebilir duruma veya yan etkiye sahip olmadan fonksiyonları kolayca geçebilir ve onlardan başka fonksiyonlar oluşturabilirim.
tdammers

@tdammers Muhtemelen çok net ifade etmedim; fonksiyonların değişebilir hale geldiğini söylediğimde veri değişebilirliğine değil, bir fonksiyonun davranışının (yüksek dereceli bir fonksiyonla) değiştirilebileceğine değindim.
m3th0dman

Üst düzey bir işlevin var olan bir işlevi değiştirmesi gerekmez; çoğu ders kitabı örneği , var olan işlevleri hiç değiştirmeden yeni işlevlerle birleştirir - mapörneğin, bir işlevi alan, bir listeye uygulayan ve sonuçların listesini döndüren. mapbağımsız değişkenlerinden hiçbirini değiştirmez, bağımsız değişken olarak aldığı işlevin davranışını değiştirmez, ancak kesinlikle daha yüksek dereceli bir işlevdir - kısmen uygularsanız, yalnızca function parametresiyle, Listede çalışan yeni işlev, ancak yine de hiçbir mutasyon olmadı.
tdammers

@tdammers: Kesinlikle: değişebilirlik yalnızca zorunlu veya çoklu paradigma dillerinde kullanılır. Bunlar daha üst düzey bir işlev (veya yöntem) ve bir kapatma kavramına sahip olsalar da, değişmezlikten vazgeçerler. Bu yararlı olabilir (bunu yapmamalıyım demiyorum) ama sorum şu anda bu işlevselliği arayabilir misiniz? Bu, genel olarak, bir kapatma işleminin kesinlikle işlevsel bir kavram olmadığı anlamına gelir.
Giorgio

@Giorgio: Klasik FP dillerin en do mutability var; Haskell, başımın üstünde değişebilirliğe izin vermeyen tek şey. Yine de, değişebilir durumdan kaçınmak FP'de önemli bir değerdir.
tdammers

9

Hayır. "İşlevsel stil" yan etkisiz programlama anlamına gelir.

Nedenini görmek için, Eric Lippert'inForEach<T> uzantı yöntemi hakkındaki blog girişine ve Microsoft'un neden Linq'de böyle bir dizi yöntemi içermediğine bakın :

İki nedenden ötürü felsefi olarak böyle bir yöntem sunmaya karşıyım.

İlk neden, bunu yapmak, diğer tüm dizi operatörlerinin dayandığı fonksiyonel programlama prensiplerini ihlal etmesidir. Açıkçası, bu yönteme yapılan bir çağrının tek amacı yan etkilere neden olmaktır. Bir ifadenin amacı, bir yan etkiye neden olmamak için bir değeri hesaplamaktır. Bir ifadenin amacı bir yan etkiye neden olmaktır. Bu şeyin çağrı sitesi, bir ifade gibi korkunç bir şey gibi görünecektir (ancak, kuşkusuz, yöntem geçersiz olduğu için, ifade sadece bir “ifade ifadesi” bağlamında kullanılabilir.) Benimle iyi oturmuyor. sadece yan etkileri için yararlı olan tek ve tek dizi operatörünü yapın.

İkinci neden, bunu yapmanın dile yeni sıfır temsil gücü katmasıdır. Bunu yapmak, bu mükemmel açık kodu yeniden yazmanıza olanak tanır:

foreach(Foo foo in foos){ statement involving foo; }

bu koda:

foos.ForEach((Foo foo)=>{ statement involving foo; });

neredeyse aynı karakterleri biraz farklı bir sırayla kullanır. Ve yine de ikinci versiyonun anlaşılması daha zor, hata ayıklaması daha zor ve kapanış semantiği getiriyor, böylece nesne yaşamlarını ince şekillerde potansiyel olarak değiştiriyor.


1
Her ne kadar ben de ona katılıyorum ... argümanı düşünürken biraz zayıflıyor ParallelQuery<T>.ForAll(...). Böyle bir uygulama IEnumerable<T>.ForEach(...)hata ayıklama için son derece yararlıdır ForAllifadeleri (replace ForAllile ForEachve kaldırmak AsParallel()ve çok daha kolay / debug onu içine girebilen)
Steven Evers

Açıkçası Joe Duffy'nin farklı fikirleri var. : D
Robert Harvey

Scala da saflığı zorunlu kılmaz: yüksek dereceli bir işleve saf olmayan bir kapanış iletebilirsiniz. Benim izlenimim, kapatma fikrinin fonksiyonel programlamaya özgü olmadığı, ancak daha genel bir fikir olduğu yönündedir.
Giorgio

5
@Giorgio: Kapaklar, yine de kapak olarak kabul edilmek için saf olmak zorunda değildir. Ancak "İşlevsel Stil" olarak değerlendirilmek için saf olmaları gerekir.
Robert Harvey

3
@Giorgio: Değişken durum ve yan etkiler etrafında bir kapanma yapmak ve başka bir işleve geçirmek gerçekten yararlıdır. İşlevsel programlamanın amaçlarına aykırıdır. Bence çok fazla kafa karışıklığı, lambdaların işlevsel dillerde yaygın olması için zarif dil desteğinden kaynaklanıyor.
GlenPeterson

0

İşlevsel programlama, birinci sınıf işlevleri kesin bir sonraki kavramsal düzeye taşır, ancak anonim işlevler bildirmek veya işlevleri diğer işlevlere geçirmek, mutlaka işlevsel bir programlama işi değildir. C'de her şey bir tamsayıydı. Bir sayı, verilere bir işaretçi, bir işleve bir işaretçi ... hepsi sadece ints. İşlev işaretleyicilerini diğer işlevlere geçirebilir, işlev işaretleyicilerinin listelerini oluşturabilirsiniz ... Heck, montaj dilinde çalışıyorsanız, işlevler gerçekten sadece makine talimat bloklarının saklandığı adreslerdir. Bir işleve bir ad vermek, kod yazmak için bir derleyiciye ihtiyaç duyanlar için ek yüktür. Yani fonksiyonlar tamamen işlevsel olmayan bir dilde "birinci sınıf" idi.

Yaptığınız tek şey bir REPL'deki matematiksel formülleri hesaplamaksa, dilinizle işlevsel olarak saf olabilirsiniz. Ancak çoğu iş programlamasının yan etkileri vardır. Uzun süren bir programın tamamlanmasını beklerken para kaybetmek bir yan etkidir. Herhangi bir harici işlem yapma: bir dosyaya yazma, veritabanını güncelleme, olayları sırayla kaydetme, vb. Bir durum değişikliği gerektirir. Bu eylemleri, kodunuzun onlar için endişelenmesine gerek kalmayacak şekilde yan etkileri ortadan kaldıran değişmez sarmalayıcılarda kapsülleyip değiştirmediğinizi tartışabiliriz. Ama bu, bir ağacın orda kimsenin duyacağı bir yere düştüğünü duyup duymadığını tartışmak gibi. Gerçek şu ki, ağaç dik başladı ve yerde sona erdi. Devlet, sadece bir şeylerin yapıldığını rapor etse bile, işler yapıldığında değişir.

Bu yüzden, siyah ve beyaz değil, gri tonları olan bir fonksiyonel saflık ölçeği ile kaldık. Ve bu ölçekte daha az yan etki, daha az değişebilirlik, daha iyi (daha işlevsel).

Aksi takdirde işlevsel kodunuzda kesinlikle yan etki veya değişken duruma ihtiyacınız varsa, onu programınızın geri kalanından en iyi şekilde kapsamaya çalışın. Yan etkileri veya değişken durumu başka şekilde saf fonksiyonlara enjekte etmek için bir kapak (veya başka bir şey) kullanmak, fonksiyonel programlamanın antitezidir. Bunun tek istisnası, kapağın geçtiği koddan yan etkileri kapsüllemek için en etkili yol olması olabilir. Hala "fonksiyonel programlama" değil ama bazı durumlarda alabileceğiniz bir dolap olabilir.

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.