Czy potrafisz nauczyć się programowania funkcjonalnego w C? [Zamknięte]


9

W wyniku dyskusji tutaj zastanawiam się, czy możesz nauczyć się programowania funkcjonalnego w C?


30
Niezależnie od tego, czy możesz, czy nie, nie powinieneś .
R. Martinho Fernandes

27
Absolutnie! Pierwszym krokiem jest napisanie tłumacza Lisp ;-)
Ferruccio

Jeśli mam rację, pytanie powinno dotyczyć uczenia się różnych pojęć za pomocą pseudokodu, bez żadnego prawdziwego języka.
SK-logic

@ SK-logic: Mówiąc łagodnie, bardzo niewielu programistów nauczyło się programowania wyłącznie za pomocą pseudokodu, większość musiała ubrudzić sobie ręce, a ich twarze splamione komunikatami o błędach z kompilatora / interpretera.
sbi

4
@sbi, niektórzy z najlepszych programistów nauczyli się programowania, gdy kompilatory nie miały żadnych komunikatów o błędach. Kodowanie na kartach perforowanych wymaga odrobiny zrozumienia tego, co robisz na długo, zanim będziesz mieć szansę na uruchomienie kodu. I nie trzeba wspominać, że podstawy programowania funkcjonalnego zostały ustalone na długo przed zbudowaniem pierwszego komputera.
SK-logic

Odpowiedzi:


21

Oczywiście można zrobić programowania funkcyjnego w teorii C., można również dowiedzieć się funkcjonalnych zasad programowania w C, ale język nie ułatwiają.

Zakładam, że masz przynajmniej trochę doświadczenia w OOP; jeśli to zrobisz, powinieneś zdawać sobie sprawę, że OOP można wykonać w C, w tym polimorfizm, metody pobierające / ustawiające, reguły widoczności itp. itp., Ale jest to dość bolesne, a musisz znać zarówno OOP, jak i C wewnątrz- wyciągnąć go. Podobnie jest z FP.

Co powinno się robić to najpierw nauczyć funkcjonalny język programowania (większość z nich ma zaskakująco prostych zasad składni, to nie jest składnia sprawia, że trudno im się nauczyć), a następnie pozwól, aby nowo nabyta wiedza wpływa na sposób zapisu C.


Zgodnie z prośbą, kilka rzeczy możesz nauczyć się od FP, a następnie zastosować, powiedzmy, C, C ++ lub Java:

  • Unikaj stanu, szczególnie wspólnego stanu zmiennego
  • Doceń czyste funkcje
  • Doceń leniwą ocenę
  • Możliwość modelowania w kategoriach czasowników zamiast rzeczowników
  • Umiejętność podejścia do problemów zarówno rekurencyjnie, jak i iteracyjnie
  • Korzystanie z funkcji wyższego rzędu
  • Myślenie o funkcjach jako o innym rodzaju wartości, którą można przekazywać i łączyć z innymi wartościami
  • Wykorzystanie pierwszorzędnych funkcji jako alternatywy dla polimorfizmu obiektowego

1
Czy możesz podać konkretne przykłady tego, w jaki sposób programiści C / C ++ / Java mogą skorzystać z mądrości LISP. Teoretycznie ma to sens, ale szukam czegoś konkretnego.
Job

@Job, jakie konkretne korzyści mogą przynieść? Rozszerza to ich umysły i może sprawia, że ​​myślą o nadmiernym stanie zmiennym jako złej rzeczy, o co więcej można prosić?
dan_waterworth

Czy mogę zatem wyciągnąć z tego wniosek, że chociaż można nauczyć się (niektórych) FP w C, nie ma sensu tego robić?
sbi

@Job: Nauczyłem się FP, gdy wiele lat temu nauczyłem się LISP jako student. Około dekady później zastosowałem FP w metaprogramowaniu szablonów.
sbi

1
@sbi, moim ulubionym sposobem uczenia się nowych języków i pojęć jest ich wdrażanie. A C to całkiem niezły język do implementacji kompilatora. Tak, tak, możesz nauczyć się FP z C.
SK-logic

11

C można zhakować, aby zaoferować pewne koncepcje funkcjonalne:

To pytanie StackOverflow powie ci więcej. Ale chociaż wydaje się możliwe wykonywanie programowania funkcjonalnego (lub dużej części) w języku C, włamania i rozszerzenia kompilatora i cokolwiek innego, co nie jest najlepszym sposobem na poznanie koncepcji.

Aby faktycznie nauczyć się programowania funkcjonalnego, najlepszym rozwiązaniem jest jeden z wiodących języków programowania funkcjonalnego, takich jak Lisp i jego dialekty ( Clojure , Scheme ), Erlang i Haskell . Każde z nich to doskonałe narzędzia, które działają w ramach funkcjonalnego sposobu programowania. F # jest również dobrym kandydatem, jeśli masz tło .Net, ale jest to język paradygmatu, a nie tylko funkcjonalny język programowania.


Jak zauważa tdammers w komentarzach:

W rzeczywistości LISP, clojure i schemat są również paradygmatem; Haskell, chociaż jest czysty i domyślnie leniwy, umożliwia także imperatywne programowanie w kontekście monadycznym i ma szerokie wsparcie dla jednoczesnego przetwarzania. Wszystkie te mają mechanizmy, które wdrażają duże części mądrości zgromadzonej w świecie OOP - enkapsulacja, dziedziczenie, jedna odpowiedzialność, kompozycja itp. Nie chodzi o to, czy język ZEZWALA na inne paradygmaty; chodzi o to, który paradygmat stanowi punkt wyjścia dla języka.

Zgodnie z moją najlepszą wiedzą Lisp i jego dialekty oraz Erlang są lepszymi kandydatami niż F #, ponieważ zachęcają do programowania funkcjonalnego w porównaniu z innymi paradygmatami, co tammers pięknie określa jako punkt wyjścia dla języka . F # obejmuje programowanie funkcjonalne, ale nie zachęca go do korzystania z innych obsługiwanych paradygmatów, programowania imperatywnego i oo.


Odnośnie twojego ostatniego zdania: W takim przypadku twierdzę, że F # jest lepszym kandydatem, ponieważ nie złapie cię w funkcjonalny sposób myślenia. W języku paradygmatu, kiedy zaczynasz wbijać śruby, możesz po prostu przełączyć się na śrubokręt. Uwięziony w jednym paradygmacie możesz nie zauważyć różnicy między śrubą a gwoździem.
R. Martinho Fernandes

Pytanie dotyczy tego, jak nauczyć się programowania funkcjonalnego, a nie programowania. Zakładam, że op ma pewne doświadczenie w języku wielu paradygmatów i chce najbardziej efektywnego sposobu nauki programowania funkcjonalnego, w którym to przypadku F # jest dobrym kandydatem, ale nie idealnym. Uwięzienie w jednym paradygmacie jest oczywiście najlepszym sposobem, gdy chcesz nauczyć się tego jednego paradygmatu, ponieważ nie musisz radzić sobie ze wszystkim, co nie jest.
yannis

Uważam, że uczenie się, kiedy paradygmat jest odpowiedni i kiedy jest nieodpowiedni do określonego zadania, jest częścią uczenia się, być może najważniejszą.
R. Martinho Fernandes

4
W rzeczywistości LISP, clojure i schemat są również paradygmatem; Haskell, chociaż jest czysty i domyślnie leniwy, umożliwia także imperatywne programowanie w kontekście monadycznym i ma szerokie wsparcie dla jednoczesnego przetwarzania. Wszystkie te mają mechanizmy, które wdrażają duże części mądrości zgromadzonej w świecie OOP - enkapsulacja, dziedziczenie, jedna odpowiedzialność, kompozycja itp. Nie chodzi o to, czy język ZEZWALA na inne paradygmaty; chodzi o to, który paradygmat stanowi punkt wyjścia dla języka.
tdammers

2
@MartinhoFernandes: Można argumentować, że uwięzienie w jednym paradygmacie jest idealnym sposobem na naukę, gdy jest to naprawdę bolesne w dupie :-)
Jörg W Mittag

2

Nie możesz nauczyć się wszystkich aspektów programowania funkcjonalnego w C. Ale z pewnością możesz rozpocząć programowanie w stylu funkcjonalnym z dowolnym językiem imperatywnym. Te bity początkowe to: „Jak zachować czystość podczas programowania”. I można to zrobić również C. Sprawdź ten post na blogu, aby uzyskać szczegółowe informacje-

http://www.johndcook.com/blog/2011/07/24/get-started-functional-programming/


2

TL; DR

Programowanie funkcjonalne dotyczy zamknięć i ich aplikacji. O ile ktoś nie jest w stanie pokazać biblioteki zamykającej zejście dla C, zapomnij o użyciu C do nauki programowania funkcjonalnego.

Co to jest programowanie funkcjonalne?

Kardynalną koncepcją programowania funkcjonalnego jest pojęcie zamknięć, które z grubsza ujmują funkcję wraz z powiązaniami zmiennych. Oprócz powszechnego użycia zamknięć, istnieje kilka innych charakterystycznych cech w programowaniu funkcjonalnym, takich jak użycie funkcji rekurencyjnych i niezmiennych wartości (obie grają dobrze razem). Te cechy są bardziej kwestią kulturową niż cokolwiek innego i nie ma technicznych przeszkód, aby używać ich w praktycznie dowolnym języku, dlatego w mojej odpowiedzi skupiam się na zamknięciach: nie każdy język pozwala na łatwe tworzenie zamknięć.

Trzy ilustracje przydatności zamknięć

Typowym zastosowaniem zamknięć jest wdrożenie mechanizmów prywatności. Na przykład kod JavaScript - w przykładach wybrałem Javascript, ponieważ jest to język funkcjonalny o tak zwanej „składni podobnej do C”, a twoje pytanie sugeruje, że znasz C:

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

Potem z

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

mamy dwie funkcje ai bliczenie rozłącznych kolekcji. Punktem przykładu jest to, że zmienne xsą przechwytywane przez zamknięcie definiujące counterzamknięcie i za każdym razem, gdy jest nowe counterzamknięcie is instantiated by the function, it gets its fresh own idea of whatx`.

Innym typowym zastosowaniem zamknięć jest definicja częściowego zastosowania funkcji. Załóżmy, że mamy funkcję raportowania podobną do syslogimplementacji funkcji

var log = function(priority, message) {

};

gdzie argumenty priorityi messageoczekuje się być ciągi, pierwszy będąc jednym "debug", "info"i tak dalej. Możemy zdefiniować fabrykę logów w następujący sposób:

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

i użyj go do zdefiniowania specjalistycznych wersji naszego narzędzia do rejestrowania:

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

Jest to bardzo przydatne, ponieważ zamiast pisać takie podatne na błędy forpętle

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

możemy napisać czystsze, krótsze i znacznie prostsze (nie ma i, to jest znacznie lepsze):

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

Trzecim ważnym obszarem zastosowania zamknięć jest wdrożenie leniwej oceny - należy pamiętać, że specjalne wsparcie językowe może zapewnić lepszą implementację.

Leniwa funkcja zamiast wykonywania prostych obliczeń zwraca zamknięcie, które można wywołać (lub „wymusić” w żargonie lenistwa) w celu wykonania pytania. Motywacją do tego jest oddzielenie przygotowywania obliczeń i wykonywania obliczeń. Praktycznym tego przykładem jest kompilacja wyrażeń regularnych: jeśli program skompiluje wiele wyrażeń regularnych w czasie uruchamiania, uruchomienie programu będzie wymagało dużo czasu. Jeśli zamiast tego leniwie skompilujemy wyrażenia regularne i wymuszymy je tak, jak potrzebujemy, nasz program może się szybko uruchomić. Oczywiście, wyrażenia regularne można tutaj zastąpić dowolną strukturą wymagającą znacznego czasu inicjalizacji.

Oto jak wdrożyć leniwą ocenę z zamknięciami. Rozważ klasyczną implementację funkcji arrayMax zwracającą maksimum w tablicy:

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

Leniwym wariantem byłoby:

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;
}

Zwrócona wartość to zamknięcie, którego można użyć do obliczenia wartości lub odzyskania jej innym razem, jeśli została już obliczona.

Dzięki tym trzem przykładom powinniśmy być pewni, że zamknięcia i ich aplikacje są podstawą programowania funkcjonalnego.

Wniosek

Nauka programowania funkcjonalnego oznacza naukę programowania z zamknięciami. W związku z tym podczas wyszukiwania języka do programowania funkcjonalnego należy wziąć pod uwagę języki umożliwiające łatwą manipulację zamknięciami, a zwłaszcza częściowe zastosowanie funkcji. I odwrotnie, języki, w których nie można łatwo manipulować zamknięciami, byłyby złym wyborem.


1
Dzięki za miłą próbkę. BTW, jak definiujesz var info, czy nie będzie to journal.forEach (info)?
ejaenv

Tak, byłby to odpowiedni wariant! :)
Michael Le Barbier Grünewald

1

Myślę, że narzędzia, których używasz, mają duży wpływ na naukę. Jest prawie niemożliwe, aby nauczyć się pojęć programistycznych, dla których używany język programowania nie zapewnia środków do wykorzystania. Jasne, zawsze możesz nauczyć się kilku rzeczy, ale nie możesz się tego właściwie nauczyć.

Ale to i tak akademicki, ponieważ, jak Martinho mówi w swoim komentarzu , nawet jeśli mogłyby uczyć się programowania funkcjonalne, to powinien nie spróbować to zrobić, ponieważ nie są w językach, gdzie jest to dużo łatwiejsze.


1

Nie powinieneś uczyć się programowania funkcjonalnego w C, ale w ścisłym języku funkcjonalnym (Haskell, Caml, Erlang itp.).

Jeśli jesteś nowy w funkcjonalnym, tak naprawdę nigdy nie dostaniesz go w niefunkcjonalnym języku. Bardziej prawdopodobne jest, że nauczysz się robić to, co uważasz za programowanie funkcjonalne i nauczysz się rzeczy w niewłaściwy sposób. I zawsze trudniej jest „nauczyć się” rzeczy we właściwy sposób, niż na początku uczyć się ich we właściwy sposób.

W każdym razie myślę, że wykonywanie funkcji w C jest dobrym ćwiczeniem dla kogoś, kto już zna funkcjonalność. Ponieważ ta osoba dowie się, co dzieje się za maską - co tak naprawdę robi komputer.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.