Jaki jest następny poziom abstrakcji? [Zamknięte]


15

Ponieważ języki programowania początkowo używały tylko wierszy kodu wykonywanych sekwencyjnie i ewoluowały w celu włączenia funkcji, które były jednym z pierwszych poziomów abstrakcji, a następnie stworzono klasy i obiekty, aby jeszcze bardziej ją wyodrębnić; jaki jest następny poziom abstrakcji?

Co jest jeszcze bardziej abstrakcyjne niż zajęcia lub czy są jeszcze jakieś?


17
Wygląda na to, że uważasz, że jest to postęp liniowy z uporządkowaniem („X jest bardziej abstrakcyjne niż Y jest bardziej abstrakcyjne niż Z”). Pozwolę sobie być innego zdania.

2
Dobrym pomysłem byłoby powiedzieć, dlaczego zaczynasz się różnić. ;) (czytaj: Jestem zainteresowany!)
sergserg

3
Proponuję ostateczną „abstrakcję”: rób to, co myślę, a nie to, co piszę. ;)
Izkata

1
@Delnan: Abstrakcja nie wprowadza całkowitego porządku, ale można powiedzieć „bardziej abstrakcyjny”, „mniej abstrakcyjny”. Na przykład ogólna implementacja sortowania scalonego jest bardziej abstrakcyjna niż implementacja sortowania scalającego, która działa tylko dla liczb całkowitych.
Giorgio

2
Bros, nauczę się teorii teorii. Następnie możemy omówić, co tak naprawdę abstrakcja oznacza cywilizowanych mężczyzn.
davidk01

Odpowiedzi:


32

Myślę, że masz jakieś nieporozumienia na temat historii komputerów.

Pierwszą abstrakcją (w 1936 r.) Był w rzeczywistości Lambda Calculus Alonzo Church, który jest podstawą koncepcji funkcji wyższego rzędu i wszystkich późniejszych języków funkcjonalnych. To bezpośrednio zainspirowało Lisp (drugi najstarszy język programowania wysokiego poziomu, stworzony w 1959 r.), Który z kolei zainspirował wszystko, od ML po Haskell i Clojure.

Drugą abstrakcją było programowanie proceduralne. Wyszło z architektur komputerowych von Neumanna, w których pisano programy sekwencyjne, jedna instrukcja na raz. FORTRAN (najstarszy język programowania wysokiego poziomu, 1958) był pierwszym językiem wysokiego poziomu, który wyszedł z paradygmatu proceduralnego.

Trzecia abstrakcja była prawdopodobnie programowaniem deklaratywnym, najpierw zilustrowanym przez Absysa (1967), a następnie Prologa (1972). Jest to podstawa programowania logicznego, w którym wyrażenia są oceniane przez dopasowanie szeregu deklaracji lub reguł, zamiast wykonywania szeregu instrukcji.

Czwartą abstrakcją było wówczas programowanie obiektowe, które po raz pierwszy pojawiło się w programach Lisp w latach 60-tych, ale później zostało zilustrowane przez Smalltalk w 1972 r. (Chociaż wydaje się, że istnieje pewna debata na temat tego, czy styl przekazywania wiadomości przez Smalltalk obiektowa abstrakcja One True. Nie zamierzam tego dotykać.)

Wszystkie inne abstrakty, zwłaszcza dotyczące tradycyjnej architektury komputerowej von Neumanna, są odmianami tych czterech tematów. Nie jestem przekonany, że poza tymi czterema istnieje inna abstrakcja, która nie jest jedynie odmianą lub kombinacją ich.

Ale abstrakcja jest w istocie jedynie sposobem na modelowanie i opisywanie algorytmu. Algorytmy można opisać jako szereg dyskretnych kroków, jako zbiór reguł, których należy przestrzegać, jako zbiór funkcji matematycznych lub jako obiekty oddziałujące. Bardzo trudno jest wymyślić inny sposób opisywania lub modelowania algorytmów, a nawet jeśli tak, to nie jestem przekonany o jego przydatności.

Istnieje jednak model obliczeń kwantowych. W obliczeniach kwantowych konieczne są nowe abstrakcje do modelowania algorytmów kwantowych. Jako neofita w tej dziedzinie nie mogę tego komentować.


4
Czy programowanie aspektowe może być uważane za kolejną formę abstrakcji?
Shivan Dragon,

Programowanie obiektowe wyszło z Lisp w latach 60.? [potrzebne źródło], wielki czas. Wszystko, co słyszałem, mówi, że wyszedł z Simuli w latach 60., który był bezpośrednim potomkiem ALGOL, imperatywnego języka, który nie miał nic wspólnego z Lispem. Smalltalk powstało, biorąc koncepcje wprowadzone przez Simulę i przekręcając je, aby poczuć się bardziej „zawstydzony”.
Mason Wheeler,

3
@MasonWheeler: Jest w podręcznikach Lisp 1 i 1.5 i często słyszy się, jak Lispers mówi o robieniu programów obiektowych, zwłaszcza starych. W tym czasie faceci AI byli wielcy w tworzeniu systemów obiektowych w Lisp.
greyfade

2
@ShivanDragon: Powiedziałbym, że nie. To tylko sposób na instrumentowanie programu proceduralnego z dodatkowymi uprzężami. Tak naprawdę nie modeluje algorytmów ani nie wydaje się wpływać na projektowanie struktur danych.
greyfade

4
W rzeczywistości rachunek kombinator SKI wyprzedza zarówno rachunek lambda, jak i maszynę Turinga.
Jörg W Mittag,

4

Dla wielu najczystszą formą abstrakcji kodu w obecnej erze programowania binarnego jest „funkcja wyższego rzędu”. Zasadniczo sama funkcja jest traktowana jako dane, a funkcje funkcji są zdefiniowane, tak jak można je zobaczyć w równaniach matematycznych z operatorami określającymi wynik ich operandów oraz z góry ustaloną kolejnością operacji definiujących „zagnieżdżanie” tych operacji. Matematyka ma bardzo mało „rozkazujących nakazów” w swojej strukturze; dwa przykłady, które mogę wymyślić, to: „niech x ma pewną wartość lub może być dowolną wartością zgodną z jakimś ograniczeniem”, oraz „częściowe funkcje”, w których dane wejściowe określają wyrażenie potrzebne do wygenerowania danych wyjściowych. Te konstrukcje są łatwo reprezentowalne jako ich własne funkcje; „funkcja” x zawsze zwraca 1, a „przeciążenie” funkcji definiuje się w kategoriach tego, co jest do nich przekazywane (które w przeciwieństwie do przeciążeń obiektowych można zdefiniować na podstawie wprowadzonych wartości), umożliwiając „częściową” ocenę nazwanej grupy funkcji, nawet pod względem samych siebie. Jako taki, program eliminuje pojęcie imperatywów na niskim poziomie i zamiast tego skupia się na „ocenieniu” danych wejściowych.

Te funkcje wyższego rzędu stanowią kręgosłup „języków funkcjonalnych”; to, co robi program, jest zdefiniowane w kategoriach „czystych funkcji” (jedno lub więcej danych wejściowych, jedno lub więcej danych wyjściowych, brak efektów ubocznych lub „ukryty stan”), które są zagnieżdżone w sobie i oceniane w razie potrzeby. W takich przypadkach większość „imperatywnej logiki” jest wyabstrahowana; środowisko wykonawcze obsługuje faktyczne wywoływanie funkcji i wszelkie warunki, w których jedno lub drugie przeciążenie funkcji może wymagać wywołania. W takim programie kod nie jest uważany za „robienie” czegoś, lecz za „bycie” czymś, a to, co dokładnie jest określane, jest uruchamiane przy początkowym wejściu programu.

Funkcje wyższego rzędu są teraz również podstawą wielu imperatywnych języków; Instrukcje lambda .NET w zasadzie pozwalają na „anonimowy” wkład funkcjonalny w inną „funkcję” (zaimplementowaną imperatywnie, ale teoretycznie nie musi tak być), umożliwiając w ten sposób wysoce konfigurowalne „łączenie” funkcji „ogólnego przeznaczenia” w celu osiągnięcia pożądany wynik.

Inną abstrakcją powszechnie spotykaną w najnowszej rundzie języków programowania jest dynamiczne pisanie zmiennych oparte na koncepcji „pisania kaczego”; jeśli wygląda jak kaczka, pływa jak kaczka, leci jak kaczka i kwakanie jak kaczka, można to nazwać kaczką. Nie ma znaczenia, czy to w rzeczywistości krzyżówka, czy płócienny obraz. Może to znaczenia, czy jest to rzeczywiście gęś lub łabędzia, ale potem znowu może to nie ważne, czy wszystko, co dbają o to, że pływa i muchy, a trochę wygląda jak kaczka. Jest to uważane za ostateczne dziedziczenie obiektu; nie obchodzi cię, co to jest , oprócz nadania mu nazwy; ważniejsze jest to, co robi. W takich językach są w zasadzie tylko dwa typy; „atom”, pojedynczy element informacji (jedna „wartość”; liczba, znak, funkcja, cokolwiek) oraz „krotka” złożona z atomu i „wskaźnika” na wszystko inne w krotce. Nie ma znaczenia, w jaki sposób te typy są implementowane w środowisku binarnym przez środowisko wykonawcze; Używając ich, możesz osiągnąć funkcjonalność praktycznie każdego rodzaju, o jakim możesz pomyśleć, od prostych typów wartości przez ciągi znaków po kolekcje (które, ponieważ wartości mogą być różnych „typów”, pozwalają na „typy złożone”, czyli „obiekty”).


1
„Pisanie z kaczką” (przynajmniej tak, jak to opisujesz) nie jest tak naprawdę nowe lub ogranicza się do dynamicznie pisanych języków; od dłuższego czasu występuje w statycznie typowanych językach jako „strukturalne podtypowanie”, najlepiej widoczne w OCaml.
Tikhon Jelvis

2

Można rozważyć języki specyficzne dla domeny, takie jak SQL, jako wyższy stopień abstrakcji. SQL jest bardzo ukierunkowanym językiem, który wyodrębnia operacje takie jak przechowywanie i zapewnia funkcje wyższego poziomu oparte na teorii mnogości. Zastanów się także, ile obecnie języków głównego nurtu nie jest ukierunkowanych na określoną architekturę, ale raczej na maszynę wirtualną (taką jak JVM lub .NET CLR). Na przykład C # jest kompilowany do IL, która jest interpretowana (lub częściej JIT'd - Just In Time Compiled - do natywnej implementacji) przez natywny silnik wykonawczy.

Dużo hałasu wzbudziło pojęcie DSL-ów używanych do tworzenia bardzo wysokiego poziomu języków, których można używać bez dużego doświadczenia technicznego do tworzenia działającego programu. Pomyśl, czy ktoś był w stanie opisać swoje byty i interakcje w prawie zwykłym języku angielskim, a środowisko operacyjne poradziło sobie z wszystkim, od przedstawienia prostego interfejsu użytkownika, po przechowywanie danych w pewnego rodzaju bazie danych. Gdy operacje te zostaną wyabstrahowane, możesz sobie wyobrazić, jak łatwe może być programowanie.

Obecnie istnieją takie, jak JetBrains MPS (zestaw narzędzi do opisywania DSL lub generatora języka). Microsoft miał krótką próbę (i mogę dodać, że jest to bardzo obiecujące) w tej przestrzeni z językiem M (język M był tak kompletny, że język został zdefiniowany w języku M).

Krytycy tej koncepcji wskazują na wcześniejsze nieudane próby usunięcia programistów z pracy nad programowaniem, różnica w porównaniu ze stołami roboczymi DSL (jak je nazywa Fowler) polega na tym, że programiści nadal byliby zaangażowani w kodyfikację koncepcji, które Eksperci domeny mogliby wyrazić potrzeby ich domeny. Podobnie jak dostawcy systemów operacyjnych i języków tworzą narzędzia, których używamy do programowania, używamy DSL do dostarczania narzędzi dla użytkowników biznesowych. Można sobie wyobrazić DSL, które opisują dane i logikę, podczas gdy programiści tworzą interpretery, które przechowują i pobierają dane oraz stosują logikę wyrażoną w DSL.


1

Twierdziłbym, że meta-struktury, moduły, frameworki, platformy i usługi są grupami cech wyższego poziomu niż klasy. Moja hierarchia abstrakcji systemu programowania:

  • usługi
  • platformy, stosy rozwiązań
  • ramy
  • moduły, pakiety
  • meta struktury: metaklasy, funkcje wyższego rzędu, generyczne, szablony, cechy, aspekty, dekoratorzy
  • obiekty, klasy, typy danych
  • funkcje, procedury, podprogramy
  • Struktury kontrolne
  • wiersze kodu

Meta-struktury, takie jak metaklasy , funkcje wyższego rzędu i generyczne wyraźnie dodają abstrakcję do podstawowych klas, funkcji, typów danych i instancji danych. Cechy, aspekty i dekoratory to nowsze mechanizmy łączenia funkcji kodu i podobnie „przyspieszające” inne klasy i funkcje.

Nawet języki poprzedzające obiekty miały moduły i pakiety, więc umieszczenie ich powyżej klas może być dyskusyjne. Bu zawierają te klasy i meta-struktury, więc oceniam je wyżej.

Frameworki to najsilniejsza odpowiedź - organizują wiele klas, meta-struktur, modułów, funkcji itp. W celu zapewnienia wyrafinowanych abstrakcji na wysokim poziomie. A jednak frameworki nadal działają prawie całkowicie w dziedzinie programowania.

Stosy rozwiązań lub platformy zazwyczaj łączą wiele środowisk, podsystemów lub komponentów w środowisko w celu rozwiązywania wielu problemów.

Wreszcie, istnieją usługi --often wdrożony jako WWW lub usług sieciowych. Są to architektury, frameworki, stosy rozwiązań lub możliwości aplikacji dostarczane jako kompletne pakiety. Ich elementy wewnętrzne są często nieprzejrzyste, przede wszystkim ujawniają interfejsy administratora, programowania i użytkownika. PaaS i SaaS są częstymi przykładami.

Teraz ten postęp może nie być w pełni satysfakcjonujący z kilku powodów. Po pierwsze, robi porządny postęp liniowy lub hierarchię rzeczy, które nie są idealnie liniowe lub hierarchiczne. Obejmuje niektóre abstrakcje, takie jak „stosy” i usługi, które nie są całkowicie kontrolowane przez programistów. I nie tworzy żadnego nowego magicznego pyłu pixie. (Spoiler: Nie ma magicznego pyłu pixie. )

Myślę, że błędem jest po prostu szukanie nowych poziomów abstrakcji . Wszystkie wymienione powyżej istniały od lat , nawet jeśli nie wszystkie były tak znane i popularne, jak teraz. Przez te lata poprawiono abstrakcje możliwe na każdym poziomie kodowania. Mamy teraz ogólne kolekcje ogólnego przeznaczenia, nie tylko tablice. Pętlujemy kolekcje, a nie tylko zakresy indeksów. Mamy zestawienia list oraz operacje filtrowania list i map. Wiele funkcji języka może mieć zmienną liczbę argumentów i / lub argumenty domyślne. I tak dalej. Zwiększamy poziom abstrakcji na każdym poziomie, więc dodanie kolejnych poziomów nie jest wymagane do zwiększenia ogólnego poziomu abstrakcji.


1

Następną abstrakcją po zajęciach są meta klasy . To takie proste ;)

klasa, której instancje są klasami. Tak jak zwykła klasa określa zachowanie niektórych obiektów, tak metaklasa określa zachowanie niektórych klas i ich instancji. Nie wszystkie zorientowane obiektowo języki programowania obsługują metaklasy. Pomiędzy tymi, które to robią, stopień, w jakim metaklasy mogą zastąpić dowolny aspekt zachowania klasowego, jest różny. Każdy język ma swój własny protokół metaobiektu, zestaw reguł rządzących interakcją między obiektami, klasami i metaklasami ...


1
Metaklasy są głównymi obiektami hierarchii dziedziczenia języka. .NET to Object. Można również myśleć o interfejsach jako o metaklasach; definiują interfejs swoich spadkobierców niezależnie od faktycznej klasy „macierzystej” spadkobiercy.
KeithS,

1
@KeithS to nie to słowo oznacza w jakimkolwiek kontekście, w jakim go widziałem - od CLOS przez UML do C #. Metaklasa jest klasą, której instancje są klasami - słaba implementacja to C #, Typektóra daje możliwości refleksyjne, ale nie mutację (nie można dodać nowej metody MyType, mówiąc typeof(MyType).Methods += new Method ( "Foo", (int x)=>x*x )jak można w CLOS)
Pete Kirkham

1

Dziwi mnie, że nikt nie wspomniał o teorii kategorii.

Najbardziej podstawową jednostką programowania jest funkcja oparta na typach. Funkcje są zwykle oznaczone jako f: A -> B, gdzie A i B są typami. Jeśli umieścisz te rzeczy, które nazywam typami i funkcjami, razem w odpowiedni sposób, otrzymasz coś, co nazywa się kategorią. W tym momencie nie musisz się zatrzymywać.

Weź te rzeczy, kategorie i zadaj sobie pytanie, jaki byłby właściwy sposób na powiązanie ich ze sobą. Jeśli zrobisz to dobrze, otrzymasz coś, co nazywa się funktorem, który przechodzi między dwiema kategoriami i jest zwykle oznaczony jako F: C -> B. Po raz kolejny nie musisz się zatrzymywać.

Możesz wziąć wszystkie funktory i złożyć je we właściwy sposób, a jeśli zrobisz to dobrze, zaczniesz zastanawiać się, jak powiązać dwa funktory ze sobą. W tym momencie otrzymujesz coś, co nazywa się naturalną transformacją, mu: F -> G, gdzie F i G są funktorami.

Moja wiedza w tym momencie staje się rozmyta, ale możesz kontynuować to i wspinać się po drabinie abstrakcji. Przedmioty i klasy nawet nie zbliżają się do opisania, jak wysoko można wspiąć się po drabinie abstrakcji. Istnieje wiele języków, które mogą wyrazić powyższe pojęcia obliczeniowo, a najbardziej znanym z nich jest Haskell. Więc jeśli naprawdę chcesz wiedzieć, na czym naprawdę polega abstrakcja, to idź nauczyć się Haskell, Agda, HOL lub ML.


1

Myślę, że brakuje modelu aktora na liście kandydatów.

Oto, co rozumiem przez aktorów:

  • niezależne podmioty
  • które odbierają wiadomości, a kiedy je odbierają, mogą
  • tworzyć nowych aktorów,
  • zaktualizuj stan wewnętrzny dla następnej wiadomości,
  • i wysyłaj wiadomości

Ten model jest czymś więcej niż deterministycznymi maszynami Turinga i jest bardziej zbliżony do naszego rzeczywistego sprzętu, gdy patrzymy na współbieżne programy. O ile nie zastosujesz dodatkowych (kosztownych) kroków synchronizacji, w dzisiejszych czasach, kiedy twój kod odbiera dane, ta wartość mogła już ulec zmianie po drugiej stronie tej samej kości, może nawet w tym samym rdzeniu.

Krótka dyskusja / wprowadzenie: http://youtube.com/watch?v=7erJ1DV_Tlo


twój post jest raczej trudny do odczytania (ściana tekstu). Czy mógłbyś edytować go w lepszym kształcie?
komar

0

Jeśli dobrze cię rozumiem, twoje „rosnące abstrakcje” można uznać za coraz większe enkapsulacje logiki, związane głównie z ponownym użyciem kodu.

Z konkretnych instrukcji wykonywanych jedna po drugiej przechodzimy do funkcji / podprogramów , które zawierają lub abstrakcyjnie logiczne grupowanie instrukcji w pojedynczy element. Następnie mamy obiekty lub moduły , które zawierają podprogramy odnoszące się do określonej jednostki logicznej lub kategorii, dzięki czemu mogę grupować wszystkie operacje na łańcuchach w ramach Stringklasy lub wszystkie typowe operacje matematyczne w Mathmodule (lub klasie statycznej, w językach takich jak C #) .

Więc jeśli to nasz rozwój, co będzie dalej? Nie sądzę, że masz wyraźny następny krok. Jak odpowiedzieli inni, twój postęp dotyczy tylko stylów programowania imperatywnego / proceduralnego, a inne paradygmaty nie podzielają twoich koncepcji abstrakcji. Ale jeśli mam coś, co może logicznie rozszerzyć twoją metaforę, to są to usługi .

Usługa jest podobna do klasy w tym sensie, że jest bytem, ​​który ujawnia funkcjonalność, ale implikuje o wiele bardziej rygorystyczne oddzielenie problemów niż w przód i w tył z obiektami, które sam tworzyłeś. Ujawniają ograniczony zestaw operacji, ukrywają wewnętrzną logikę i nawet niekoniecznie działają na tym samym komputerze.

Ponownie istnieje dobre rozróżnienie. W większości przypadków użyjesz obiektu, który działa jako serwer proxy dla usługi , a oba będą bardzo podobne, ale jako architektura oba są różne.


0

Nowe formy abstrakcji ukrywają przed tobą pracę na niskim poziomie. Nazwane procedury i funkcje ukrywają przed tobą adresy programów. Obiekty ukrywają dynamiczne zarządzanie pamięcią i niektóre zależne od typu „instrukcje if”.

Sugerowałbym, że następnym poziomem praktycznych abstrakcji, które będą ukrywać przed tobą nudy na niskim poziomie, są funkcjonalne programowanie reaktywne . Spójrz na „sygnały” w czymś takim jak http://elm-lang.org/, które ukrywają wywołania zwrotne i aktualizują zależności, które musicie jawnie zarządzać w javascript. FRP może ukryć dużą złożoność komunikacji między procesami i komunikacji między maszynami, która jest potrzebna w aplikacjach internetowych na dużą skalę, a także w wysokiej wydajności równoległości.

Jestem prawie pewien, że właśnie to nas ekscytuje w ciągu najbliższych 5 lat.


1
FRP jest świetny, ale zajmuje się dość specyficznym rodzajem programowania (mianowicie programowaniem reaktywnym ). Nie jest zbyt dobry do modelowania innych rodzajów programów. Jednak bardziej ogólny rodzaj programowania, jaki reprezentuje - pisanie kodu w kategoriach algebry - jest dobrym kandydatem na nowy poziom abstrakcji.
Tikhon Jelvis

0

Teoria zbiorów - częściowo zaimplementowana w relacyjnych bazach danych, ale także w językach statystycznych takich jak SAS i R, zapewnia inny, ale prawdopodobnie wyższy poziom abstrakcji niż OO.

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.