C de fonksiyonel programlamayı öğrenebilir misiniz? [kapalı]


9

Buradaki yorum tartışmasının bir sonucu olarak, C de Fonksiyonel Programlamayı öğrenip öğrenemeyeceğinizi merak ediyorum.


30
Yapıp yapamayacağınız konusunda, yapmamalısınız .
R. Martinho Fernandes

27
Kesinlikle! İlk adım Lisp tercümanı yazmak ;-)
Ferruccio

Ben doğru, o soru olmadan, pseudocode çeşitli kavramları öğrenme konusunda olması gereken herhangi hepsi gerçek dili.
SK-logic

@ SK-logic: Hafifçe söylemek gerekirse, çok az programcı tamamen sahte kodla programlamayı öğrendi, çoğunun ellerini kirletmesi ve yüzlerinin derleyiciden / yorumlayıcıdan gelen hata mesajları ile dolması gerekiyordu.
sbi

4
En iyi programcılardan bazıları derleyicilerin hiçbir hata mesajı almadığında programlamayı öğrendi. Delikli kartlarda kodlama yapmak, kodu çalıştırma şansınız olmadan çok önce ne yaptığınızı anlamayı gerektirir. Ve fonksiyonel programlama için temelin ilk bilgisayar inşa edilmeden çok önce kurulduğundan bahsetmeye gerek yok.
SK-logic

Yanıtlar:


21

Açıkçası yapabilirsiniz do C. In teoride fonksiyonel programlama, ayrıca edebilirsiniz öğrenmek C fonksiyonel programlama prensiplerini, ama dil kolay yapmaz.

OOP'de en azından biraz geçmişiniz olduğunu varsayıyorum; bunu yaparsanız, OOP'nin polimorfizm, alıcılar / ayarlayıcılar, görünürlük kuralları vb. çıkarın. FP ile aynı şey.

Yapmanız gereken ilk önce işlevsel bir programlama dili öğrenmek (çoğu şaşırtıcı derecede basit sözdizimi kurallarına sahiptir; öğrenmelerini zorlaştıran sözdizimi değildir) ve sonra yeni edinilen bilgeliğinizin C yazma şeklinizi etkilemesine izin verin.


İsteğe bağlı olarak, FP'den öğrenebileceğiniz ve sonra C, C ++ veya Java'da uygulayabileceğiniz birkaç şey:

  • Durumdan, özellikle paylaşılan değiştirilebilir durumdan kaçının
  • Saf fonksiyonları takdir edin
  • Tembel değerlendirmeyi takdir edin
  • İsimler yerine fiiller açısından modelleme yapabilme
  • Sorunlara yinelemeli ve yinelemeli olarak yaklaşabilme
  • Üst düzey işlevleri kullanma
  • İşlevleri başka bir değer olarak düşünmek, etrafta dolaşmak ve diğer değerlerle birleştirmek
  • Birinci sınıf fonksiyonları nesne tabanlı polimorfizme alternatif olarak kullanma

1
C / C ++ / Java programcılarının LISP bilgeliğinden nasıl faydalanabileceğine dair spesifik örnekler verebilir misiniz? Teoride mantıklı, ama somut bir şey arıyorum.
İş

@ İş, Ne gibi somut faydalar olabilir? Zihinlerini genişletir ve belki de aşırı değişebilir durumu kötü bir şey olarak düşünmelerini sağlar, daha ne isteyebilirsin?
dan_waterworth

Öyleyse, C'den (bazı) FP öğrenmek mümkün olsa da, bunu yapmanın bir anlamı olmadığı sonucuna varabilir miyim?
sbi

@ İş: Uzun yıllar önce LISP'yi öğrenci olarak öğrendiğimde FP'yi öğrendim. Yaklaşık on yıl sonra FP'yi şablon meta programlamasına uyguladım.
sbi

1
Yeni dilleri ve kavramları öğrenmenin en sevdiğim yolu onları uygulamaktır. Ve C, bir derleyici uygulamak için oldukça iyi bir dildir. Yani, evet, C ile FP öğrenebilirsiniz
SK-logic

11

C bazı fonksiyonel kavramlar sunmak için saldırıya uğrayabilir:

Bu StackOverflow sorusu size daha fazlasını anlatacaktır. Ancak, C, bilgisayar korsanları ve derleyici uzantıları ve bir kavram öğrenmenin en iyi yolu ne değilse, işlevsel programlama (veya büyük bir alt kümesi) yapmak mümkün gibi görünse de.

Fonksiyonel programlamayı gerçekten öğrenmek için en iyi seçeneğiniz Lisp ve lehçeleri ( Clojure , Scheme ), Erlang ve Haskell gibi önde gelen fonksiyonel programlama dillerinden biridir . Bunlardan herhangi biri, işlevsel programlama zihniyeti içinde çalışan mükemmel araçlardır. F # , aynı zamanda .Net arka planınız varsa iyi bir adaydır, ancak çok işlevsel bir programlama dili değil, çok paradigma dilidir.


Tdammers'ın açıklamalarda belirttiği gibi :

Aslında, LISP, clojure ve şema da çok paradigmadır; Haskell, saf ve varsayılan tembel olmakla birlikte, monadik bir bağlamdayken zorunlu programlamaya da izin verir ve eşzamanlı işleme için geniş bir desteğe sahiptir. Bunların hepsinin OOP dünyasında toplanan bilgeliğin büyük bölümlerini uygulayan mekanizmaları vardır - kapsülleme, miras, tek sorumluluk, kompozisyon, vb. hangi paradigmanın bir dilin başlangıç ​​noktasını oluşturduğu ile ilgilidir.

Diğer paradigmaların üzerinde fonksiyonel programlama teşvik çünkü benim kadarıyla Lisp ve lehçeleri ve Erlang F # daha iyi adaylardır ne tdammers güzelce olarak bildiren bir dilin başlangıç noktası . F #, işlevsel programlamayı kapsar, ancak diğer desteklenen paradigmaları, zorunlu ve oo programlarını teşvik etmez.


Son cümlenizle ilgili olarak: Bu durumda F # 'ın daha iyi bir aday olduğunu iddia ediyorum çünkü işlevsel bir zihniyete hapsolmayacak. Çok paradigma dilinde, vidaları çekiçlemeye başladığınızda, sadece bir tornavidayı kullanabilirsiniz. Tek bir paradigmada sıkıştığında vida ve çivi arasındaki farkı kaçırabilirsiniz.
R. Martinho Fernandes

Soru, programlama değil, fonksiyonel programlamanın nasıl öğrenileceğidir. Op'un çok paradigma dilinde bir tecrübeye sahip olduğunu ve fonksiyonel programlamayı öğrenmek için en verimli yolu istediğini varsayıyorum, bu durumda F # iyi bir aday ama mükemmel bir aday değil. Tek bir paradigmada mahsur kalmak , o tek paradigmayı öğrenmek istemediğinizde en iyi yoldur, çünkü o olmayan her şeyle uğraşmak zorunda kalmazsınız.
yannis

Paradigmanın uygun olduğu ve belirli bir görev için uygun olmadığı zaman öğrenmenin, belki de en önemlisi, öğrenmenin bir parçası olduğuna inanıyorum.
R. Martinho Fernandes

4
Aslında, LISP, clojure ve şema da çok paradigmadır; Haskell, saf ve varsayılan tembel olmakla birlikte, monadik bir bağlamdayken zorunlu programlamaya da izin verir ve eşzamanlı işleme için geniş bir desteğe sahiptir. Bunların hepsinin OOP dünyasında toplanan bilgeliğin büyük bölümlerini uygulayan mekanizmaları vardır - kapsülleme, miras, tek sorumluluk, kompozisyon, vb. Bir dilin diğer paradigmalara İZİN VERDİĞİ; hangi paradigmanın bir dilin başlangıç ​​noktasını oluşturduğu ile ilgilidir.
tdammers

2
@MartinhoFernandes: Tek bir paradigmada mahsur kalmanın gerçekten kıçta bir acı olduğunu öğrenmek için mükemmel bir yol olduğunu söyleyebiliriz :-)
Jörg W Mittag


2

TL; DR

Fonksiyonel programlama, kapaklar ve uygulamaları ile ilgilidir. Birisi size C için bir iniş kapatma kütüphanesi gösteremezse, fonksiyonel programlamayı öğrenmek için C'yi kullanmayı unutun.

Fonksiyonel programlama nedir?

Fonksiyonel programlamanın temel konsepti, kabaca konuşan, değişken bağlarla birlikte bir işlevi yakalayan kapaklar kavramıdır . Kapakların yaygın kullanımının yanı sıra, fonksiyonel programlamada, özyinelemeli işlevlerin ve değişmez değerlerin kullanılması gibi her iki ayırt edici özellik de vardır (her ikisi de birlikte iyi oynar). Bu özellikler her şeyden çok kültürel bir konudur ve bunları hemen hemen her dilde kullanmanın teknik bir engeli yoktur, bu yüzden cevabımdaki kapanışlara odaklanıyorum: her dil kolayca kapanmaya izin vermiyor.

Kapakların kullanışlılığının üç resmi

Kapakların tipik kullanımı gizlilik mekanizmalarının uygulanmasıdır. Örneğin Javascript kodu - Örneklerde Javascript'i seçtim çünkü “C benzeri bir sözdizimi” olan işlevsel bir dil ve sorunuz C'ye aşina olduğunuzu gösteriyor:

create_counter = function()
{
  var x = 0;
  var counter = function()
  {
    ++x;
    return x;
  };
  return counter;
}

Sonra ile

a = create_counter();
b = create_counter();

iki fonksiyonumuz var ave bayrık koleksiyonları sayıyoruz. Örneğin amacı, değişkenlerin xkapağı tanımlayan kapak tarafından yakalanması counterve her yeni counterkapak is instantiated by the function, it gets its fresh own idea of whatx` olduğunda.

Kapakların bir başka tipik kullanımı, işlevlerin kısmi uygulamalarının tanımlanmasıdır. syslogBir işlevi uygulamaya benzer bir raporlama tesisimiz olduğunu varsayın

var log = function(priority, message) {

};

argümanlar nerede priorityve messagedizeleri olması bekleniyor, ilki biri olmak "debug", "info"vb. Bir günlük fabrikasını şu şekilde tanımlayabiliriz:

var logWithPriority = function(priority) {
  return function(message) {
    log(priority, message);
  };
};

ve günlük tesisimizin özel sürümlerini tanımlamak için kullanın:

var debug = logWithPriority("debug");
var info = logWithPriority("info");

Bunun nedeni yerine hataya yazma, çok yararlıdır forböyle -loops

for(i = 0; i < journal.length; ++i) {
   log("info", journal[i]);
}

daha temiz, daha kısa ve daha basit yazabiliriz (hayır i, bu çok daha iyi):

journal.forEach(logWithPriority("info"));

Kapakların üçüncü önemli uygulama alanı, tembel değerlendirmenin uygulanmasıdır - özel dil desteğinin daha iyi bir uygulama sağlayabileceğini unutmayın.

Tembel bir işlev, düz bir hesaplama yapmak yerine, soruyu gerçekleştirmek için çağrılabilen (veya tembellik jargonunda “zorla”) bir kapatma döndürür. Bunu yapmak için motivasyon, bir hesaplama hazırlamak ve bir hesaplama yapmak arasında ayrım yapmaktır. Bunun pratik bir örneği düzenli ifade derlemesidir: bir program başlangıç ​​zamanında çok sayıda düzenli ifade derlerse, başlamak için çok zaman gerekir. Bunun yerine düzenli ifadeleri tembel olarak derler ve ihtiyaç duyduğumuzda zorlarsak, programımız hızlı bir şekilde başlayabilir. Tabii ki, düzenli ifadeler burada önemli ölçüde başlatma süresi gerektiren herhangi bir yapı ile değiştirilebilir.

Tembel değerlendirmenin kapanışlarla nasıl uygulanacağı aşağıda açıklanmıştır. Bir dizideki max değerini döndüren arrayMax işlevinin klasik uygulamasını düşünün :

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  };
}

Tembel varyant:

function arrayMax(array) {
  var memo = null;
  function actuallyCompute() {
    if(memo === null) {
      memo = array.reduce(function(a, b) {
        return Math.min(a, b);
      });
    }
    return memo;
  }
  return actuallyCompute;
}

Döndürülen değer, değeri hesaplamak veya zaten hesaplanmışsa başka bir zaman almak için kullanılabilen bir kapaktır.

Bu üç örnekle, kapakların ve uygulamalarının fonksiyonel programlamanın çekirdeği olduğundan emin olmalıyız .

Sonuç

Fonksiyonel programlamayı öğrenmek, kapaklarla nasıl programlanacağını öğrenmek anlamına gelir. Sonuç olarak, işlevsel programlamayı incelemek için bir dil ararken, kapakların kolayca değiştirilmesine izin veren diller ve özellikle işlevlerin kısmi uygulanması dikkate alınmalıdır. Tersine, kapakların kolayca değiştirilemediği diller kötü seçimler olacaktır.


1
Bu güzel örnek için teşekkürler. BTW, var info tanımladığınız gibi, journal.forEach (info) olmaz mı?
ejaenv

Evet, uygun bir varyant olurdu! :)
Michael Le Barbier Grünewald

1

Kullandığınız araçların öğrenmenizi çok etkilediğini düşünüyorum. Kullandığınız programlama dilinin yararlanmanın yollarını sağlamadığı programlama kavramlarını öğrenmek neredeyse imkansızdır. Elbette, her zaman birkaç şey öğrenebilirsiniz, ancak düzgün bir şekilde öğrenemezsiniz.

Olarak, çünkü Ama bu, akademik zaten olan Martinho onun yorumunda diyor sen bile olabilir fonksiyonel programlamayı öğrenmek, sen gereken bu olduğu diller olduğundan, bunu çalışmayın çok daha kolay.


1

İşlevsel programlamayı C dilinde değil, katı bir işlevsel dilde (Haskell, Caml, Erlang, vb.) Öğrenmelisiniz.

İşlevsel olarak yeniyseniz, bunu gerçekten işlevsel olmayan bir dille elde edemezsiniz. Büyük olasılıkla, fonksiyonel programlama olduğunu düşündüğünüz şeyi yapmak ve işleri yanlış bir şekilde öğrenmek için kendinizi eğiteceksiniz. Ve her şeyi doğru şekilde “yeniden öğrenmek”, ilk başta onları doğru şekilde öğrenmekten daha zordur.

Her neyse, C'de fonksiyonel yapmak zaten fonksiyonel bilen biri için iyi bir egzersiz. Çünkü o kişi kaputun arkasında neler olduğunu öğrenecek - bilgisayarın gerçekte ne yaptığını.

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.