Birinci Sınıf Fonksiyonlar


11

Ciddi bir şekilde bu hafta sonu Lisp'e bir göz atmaya başladım. Diğer işlevsel dillerle (F #, Haskell, Erlang) dabbledim ama Lisp'in bana verdiği çekilişi hissetmedim.

Şimdi Lisp'i öğrenmeye devam ederken, işlevsel olmayan dillerin neden birinci sınıf işlevleri desteklemediğini merak etmeye başladım. C # gibi delegelerin delegelerle benzer şeyler yapabileceğini biliyorum ve bir dereceye kadar C / C ++ 'da işlevler için işaretçiler kullanabilirsiniz, ancak bunun bu dillerde hiçbir zaman bir özellik haline gelmemesinin bir nedeni var mı? Birinci sınıf fonksiyonları yapmak için bir dezavantaj var mı? Benim için son derece yararlı, bu yüzden neden daha fazla dilin (işlevsel paradigmanın dışında) onu uygulamadığı için kayboldum.

[Düzenle] Şimdiye kadar verilen cevapları takdir ediyorum. Birçok dilin artık birinci sınıf işlevleri desteklediğini göstermiş olduğum için, soruyu dillerin uygulaması neden bu kadar uzun sürecek? [/Düzenle]


3
C # "benzer şeyler" yapabileceğini katılmıyorum. Tüm niyetler ve amaçlar için birinci sınıf fonksiyonlara sahip olduğunu söyleyebilirim (hangi tür öncülerinizi mahveder). Fonksiyon değişmezleri için bir sözdizimi vardır, işlevleri değişkenlere vb.
Doldurabilirsiniz

@Logan - Ben C # örnekleri dahil olup olmadığını tartışıyordu ama bu wikipedia girişi dayalı karar verdi . Girdiye göre, "işlevin dinamik durumunu tutan nesnelerin manuel olarak oluşturulması gerektiğinden" gerçek birinci sınıf işlevler yoktur. Ancak, bu yanlış bir ifade ise, nedenini bilmek isterim! (Sonuçta, öğrenmek için buradayım ve
yolumda takılı kalmıyorum

2
wikipedia girişi eski. Modern bir C #, uygun bir lambda sağlar.
SK-logic

Bence bu paragraf kötü yazılmış. Görünüşe göre C ++ functors birinci sınıf değildir ve ikisi de C # delegeleri değildir? Functors argümanını kabul edebilirken, C # delegeleri için yapacağımdan emin değilim. Ayrıca, "değerler olarak işlevler" yerine sözcüksel kapanışları destekleyen bu diller hakkında bir açıklama olan "(lambda kaldırma)" yazıyor. Biri olmadan diğeri olabilir. Durum böyle olsa bile, C # için doğru değildir, sözlüksel kapanışları vardır. Sorunun bir kısmı "birinci sınıf işlev" belirsiz bir terim olabilir.
Logan Capaldo

1
@Logan & SK-Logic - Geri bildiriminiz ve yapıcılığınız için teşekkür ederim. Hala öğreniyorum ve alev almamak çok güzel, bu yüzden bunu takdir ediyorum. Yorumlar ve cevaplar için çok teşekkürler!
Jetti

Yanıtlar:


5

C #, VB.NET, Python, JavaScript, şimdi bile C ++ 0x birinci sınıf işlevler sunmaktadır.

Güncelleme:

Kapakların uygulanması, zorunlu programcılar için başlangıçta oldukça yabancı bir teknik olan lambda kaldırma gerektirir. Uygun birinci sınıf işlevler (kapanışları içerir), çalışma zamanından ve VM'den en azından biraz destek gerektirir. Ayrıca, eski işlevsel teknikleri zorunlu dünyaya uyarlamak biraz zaman aldı.

Ve en önemli kısım - mevcut çöp toplama yoksa birinci sınıf fonksiyonlar neredeyse hiç kullanılamaz. Sadece son zamanlarda Java ve sonuç olarak .NET ile bir kitle programlamaya sokuldu. Ve orijinal Java yaklaşımı, dili ortalama kodlayıcılar tarafından karşılaştırılabilir tutmak için dili basitleştirmekti. .NET ilk izledi ve sadece son zamanlarda bu (IMHO, oldukça haklı ve uygun) yönden ayrıldı.

Tüm bu kavramların endüstri tarafından sindirilmesi zaman alır.


Yanıtları temel alarak orijinal soruyu düzenledim.
Jetti

Birinci sınıf fonksiyonlar! = Kapaklar (ve GC, ikincisi için çok daha fazla gereklidir). Her ne kadar, evet, onlar yakından ilişkilidir ve nadiren, eğer varsa, onları ayrılmış olarak görürsünüz.

@delnan, en azından bir tür sözcüksel kapatma işlevi olmadan, birinci sınıf işlev tanımlaması için zorunlu olan çalışma zamanında oluşturulamaz ve yapılamaz.
SK-logic

Hayır olabilir kapsamları içine değişkenler atıfta izin vermemek (veya işlev oluşturma sırasında anılan değişkenin değerlerini kopya - Bilmem eğer kapanması olarak bu sayımlar). Sonuç özellikle yararlı değildir, ancak işlevler kapanış olmadan çalışma zamanında oluşturulabilir ve bu nedenle (garip) birinci sınıf işlevleriniz olur.

1
@ SK-logic: C ++ 0x her zamanki hile ile çöp toplama olmadan kapanış sağlar -> değişken kapsam dışına çıkar ve hala bir referansa tutunuyorsanız, referansı kullanmak tanımsız bir davranıştır. Bu yüzden mümkün ... sadece honus'u geliştiriciye koyuyor.
Matthieu M.Feb

5

Birinci sınıf fonksiyonlar kapanmadan çok daha az ilgi çekicidir.

Kapsama alanı bir tür dinamik yönetim (çöp toplama) olmadan gerçekten mümkün değildir. C / C ++ 'ı bu kadar yüksek performans gösteren şeylerden biri, hafızayı manuel olarak yönettiğiniz bir dili derlemenin çok daha kolay olmasıdır, böylece C / C ++' ı denklemden çıkarır.

Ve sonra evet, OOP etkisi var. Artık yöntem ve özellik ayrımına sahip değilsiniz. Yöntemler, fonksiyonları değer olarak kabul eden özelliklerdir. Bu bağlamda, aptalca şeyleri istediğiniz zaman değiştirebildiğiniz için, aşırı yük yöntemlerine gerçekten ne anlama geliyor? Örneğin, tüm dile büyük bir paradigma kayması getirmeden bunu Java'ya gerçekten ekleyebilir misiniz? Sözleşme ya da insanların (IMO yanlış) güvenlik hissi, yapı garantilerini bilmekten her zaman her zaman aynı şekilde çalışacağını biliyor mu? Nesnelere bağlı işlevleri, işlevlerin ilk etapta bağımsız olarak var olmasına izin veren dillerde farklı bir organizma olarak yöntem olarak ele almak mantıklı olabilir, ancak Java'da bu gerçekten bir seçenek değildir.

JavaScript, OOP ve fonksiyonel çok iç içe ve ben şahsen birinci sınıf fonları olmayan bir dilde cıvatalı ama bir şey olarak görmek zor bulurdum. Ancak bu, nesnelerde ve yöntemlerinin kendilerinde yüksek düzeyde değişebilirlik de dahil olmak üzere birçok paradigma değiştiren değişikliklerin yanı sıra işlevleri anında herhangi bir nesnenin üyeleriymiş gibi çağırabilmeyi gerektirir.

Diller, işlerin çoğunu yapmak için sadece do-hickey'lerle dolu araç setleri değildir. Onlar paradigmalar. Her türün birbirine bağlı (veya bağlantılı gibi) bir şekilde bir araya getirdiği fikir, strateji ve fikir demetleri. Birçok durumda isim ve fiil gibi işlevler gerçekten paradigmaya hiç uymuyor ya da en iyi ihtimalle kusursuz bir uyum.

Dedi ki, onlarsız kodlamaya zorlandığımda bir kolum eksik gibi hissediyorum.


Tüm yöntemleri mühürlü olarak ele alabilir veya en çok önem verdiklerinizi mühürleyebilirsiniz ve iyi olacaksınız.
Alexei Averchenko

@AlexeiAverchenko Bununla ne demek istediğinden% 100 emin olmadığımı söylemekten mutluluk duyuyorum. Üzgünüm, şimdiye kadar yorumunu kaçırdım. Google "mühürlü yöntemler."
Erik Reppen

4

Gerçekten imkansız değil. Ama yine de başka bir özellik ve karmaşıklık bütçesi sınırlı. Dil tasarımcısı tarafından gereksiz görülebilir (hatta gerçekleşmez) - "neden heck fonksiyonları çevirmemiz gerekiyor? Bu dil bir işletim sistemi programlamak içindir!". Dilin geri kalanıyla birleşmek de önemli çaba harcayabilir. Örneğin, bir işlev türü, aşırı yüklemeniz varsa, tür sistemine (örneğin Java'da) ciddi eklemeler gerektirebilir (bunu belirttiğiniz için @Renesis'e teşekkürler). Geçerli olanı kullanmak için bazı kütüphane kodu sağlamanız gerekir - kimse mapkendilerini tanımlamak istemez .

Dilin diğer hedeflerine ulaşmak da daha zor olabilir:

  • Optimize etmek "zor" hale gelir (çoğu durumda aslında daha zor değildir, ancak alışkın olduğunuzdan farklı yaklaşımlar gerektirir). Örneğin, global işlevler yeniden atanabiliyorsa, fsatır içi olmadan önce yeniden atanmadığını kanıtlamanız gerekir.
  • Benzer bir şekilde, fonksiyonları tam özellikli nesneler yaparsanız, bununla ilişkili ek yükü kaldırmak ve argümanları itmek ve adresi döndürmek ve adrese atlamak kadar verimli (hız ve boşluk açısından) çağrı yapmak için akıllı bir derleyiciye ve JIT'e ihtiyacınız vardır . bazı adres.
  • Daha önce bahsedildiği gibi, başka bir tam özellik ve henüz başka bir paradigma destekleme yolunda ilk adımlar - sen basit bir dil istiyorsanız, belki de göze alamaz (eğer çok daha önemli hangileri olduğundan) başka şeyler atma olmadan birinci sınıf işlevleri eklemek için dışarı.
  • Belki de sadece dilin geri kalanıyla iyi uyum sağlamaz. Dili, Smalltalk'tan beri OOP'un en iyi enkarnasyonu olacak şekilde tasarlarsanız, başka, çok farklı bir paradigma sunmak yerine bu dile odaklanmak isteyebilirsiniz. Özellikle ikisini entegre etmek zorsa (yukarıya bakınız). İyi yapılan N paradigmaları programlamak kötü yapılan N + 1 paradigmalarından daha hoştur.

Aynı şekilde, herhangi bir L1 programlama dilinin neden çok farklı L2 dilinin F özelliğine sahip olmadığını sorabilirsiniz.


1

Bence ilk sorun Nesneye Dayalı ve Fonksiyonel'in karıştırılamayacağı bir yanlış anlama. En azından Wikipedia tarafından her ikisi olarak açıklanan hızlı bir dil listesi: JavaScript , ActionScript , Python , C # , F # .

İkinci problem birinci sınıf fonksiyonların bir tanımı gibi görünüyor - neden C # 'a sahip olduklarını düşünmüyorsunuz?

İşlevsel bir dil uzmanı değilim, bu yüzden lütfen eğer yanlışsam yorumlarda beni düzeltin, ancak benim anlayışım, birinci sınıf işlevlerinin dahil edilmesinin, bir dilin işlevsel bir paradigmayı destekleyip desteklemediğini tanımlamasıdır .

Asıl soru nedir?

Bu nedenle, nesne yönelimli dillerin işlevsel olabileceğini ve bu dillerin birinci sınıf işlevleri içerdiğini anlamak, aradığınız soruya benziyor, bazı nesne yönelimli diller neden birinci sınıf işlevler içermiyor?

Fonksiyon aşırı yüklenmesi

Bunun başlıca nedenlerinden biri, dil işlev aşırı yüklemesini de desteklemeyi seçtiğinde birinci sınıf işlevleri tanımlamanın güçlüğüdür ( Java'da örnek):

public int dispatchEvent(Event event);
public int dispatchEvent(String event, Object data);

dispatchEventBir değişken hangi fonksiyona atıfta bulunur?

Sınıf tabanlı programlama

Sınıf tabanlı programlama, bir dilin birinci sınıf nesneleri desteklemesini engellemez, ancak daha karmaşık hale getirebilir veya yanıtlanması gereken sorular ekleyebilir.

Örneğin, bir ECMAScript dili olarak ActionScript, JavaScript gibi çok daha işlevsel bir paradigmada başladı. İşlevler doğal olarak nesnelere bağlı değildi, aslında yürütme sırasındaki kapsamı olarak herhangi bir nesne ile çağrılabilirlerdi.

(Dinamik olmayan) sınıflar eklediğinizde , yalnızca sınıfın kendisine değil, bir örneğe doğal olarak bağlı işlevleriniz vardır . Bu, Function.applydürüstçe bununla nasıl başa çıktıklarını bulmak için kazmadığım spesifikasyona birkaç kırışıklık atıyor .


3
"Birinci sınıf işlevlerin dahil edilmesi, az çok bir dili işlevsel kılar." - Yanlış. Bu bir önkoşul, evet. Ancak, değişebilir durumdan kaçınmak, sıralı ifadelerden ziyade ifadelere ve işlev uygulamasına odaklanmak ve referans şeffaflığına vurgu yapmak gibi (sadece üçünü adlandırmak) çok daha fazlası var.

@delnan Wikipedia'yı düzeltmelisin ... "İşlevsel bir dil" ve "işlevsel bir paradigmayı destekleyen dil" iki farklı şey olmadıkça.
Nicole

1
@Rensis: Bunlar farklı şeyler. C'de nesneler (hatta vtables dahil) gibi bir şey oluşturabilirsiniz, ancak bu hoş değil. "Birinci sınıf işlevleri" den "işlevsel bir dil" e geçiş o kadar da kötü değil, ama yine de bir fark. Ayrıca, wiki (doğru) bağlandığınız sayfada "Bu özellikler işlevsel programlama stili [...] için bir gerekliliktir ." (yani: "tanımlayıcı özellik" değil) ve FP'deki sayfada birkaç başka özellik listeler.

@ delnan, Pekala, ifadelerimi düzelttim. Sadece bir dilin işlevsel bir paradigmayı desteklediği düşünülmek koşulunu kastettim - listelediğim her dil için Wikipedia sayfası. İşlevsel programlama tarzının bir parçası olduğunu söylemek istemedim .
Nicole

0

Ben de aynı şeyi merak ettim. Lambdas ile bir dilde olduğumda onlara çok kullanıyorum. Php 5.3 ile bir kapatma yapabileceğinizi fark ettiğinizde PHP bile daha iyi olur (lisp kadar hoş değil, ama yine de daha iyi)

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.