Co oznacza „reifikacja” i „reifikacja” w kontekście programowania (funkcjonalnego?)?

82

Często czytam ten termin na blogach o haskell i programowaniu funkcjonalnym (szczególnie na blogu sigfpe ), ale nie mam pojęcia, co to znaczy. Przez większość czasu udaje mi się nie wiedzieć, ale prawdopodobnie zrozumiałbym teksty dużo lepiej, gdybym wiedział. Google mi nie pomogło. Gubię się w sprawach technicznych.

Również nietechniczne znaczenie świata („obracanie abstrakcyjnego konkretu”) nie pomaga mi zrozumieć, co w praktyce oznacza reifikacja czegoś w kodzie.

Jestem trochę powolny z koncepcjami informatycznymi, więc praktyczne przykłady z kodem byłyby fajne. : P

Rafael S. Calsaverini
źródło

Odpowiedzi:

42

Czytałem więc o tym, co to właściwie oznacza: przyjęcie abstrakcyjnej koncepcji i uczynienie jej konkretną. Lub istnieje proxy, które reprezentuje abstrakcyjne pojęcie. Na przykład w Lispie koncepcja abstrakcji procedury i aplikacji jest reifikowana, gdy używasz lambd.

Reifikacja sama w sobie jest pojęciem szerokim i nie ma zastosowania tylko do funkcjonalnych języków programowania.

Na przykład w Javie istnieją typy dostępne w czasie wykonywania. To są typy reifable. Oznacza to, że istnieje konkretna reprezentacja abstrakcyjnej koncepcji typu w czasie wykonywania. W przeciwieństwie do tego istnieją typy niewymienialne. Jest to szczególnie widoczne podczas używania typów ogólnych w Javie. W Javie typy generyczne podlegają wymazaniu typów, więc ogólne informacje o typie nie są dostępne w czasie wykonywania (chyba że sparametryzowany typ używa nieograniczonych symboli wieloznacznych).

Innym przykładem jest próba modelowania koncepcji. Na przykład załóżmy, że masz Groupklasę i Userklasę. Teraz istnieją pewne abstrakcyjne pojęcia, które opisują związek między nimi. Na przykład abstrakcyjne pojęcie Userbycia członkiem a Group. Aby ta relacja była konkretna, napisałbyś metodę o nazwie, isMemberOfktóra mówi, czy a Userjest członkiem a Group. Więc to, co tutaj zrobiliście, to zreifikowanie ( urealnienie / wyraźne / konkretne) abstrakcyjnej koncepcji członkostwa w grupie.

Innym dobrym przykładem jest baza danych, w której istnieją relacje rodzic-dziecko między obiektami. Możesz opisać ten związek w abstrakcyjnym pojęciu drzewa. Teraz załóżmy, że masz funkcję / metodę, która pobiera te dane z bazy danych i konstruuje rzeczywisty Tree obiekt. To, co teraz zrobiłeś, to ujednolicenie abstrakcyjnej koncepcji relacji drzewo rodzic-dziecko w rzeczywisty Tree obiekt.

Wracając ogólnie do języków funkcjonalnych, być może najlepszym przykładem reifikacji jest stworzenie samego języka programowania Lisp. Lisp był konstruktem całkowicie abstrakcyjnym i teoretycznym (w zasadzie tylko matematyczną notacją języków komputerowych). Tak było, dopóki evalfunkcja Lispa nie została faktycznie zaimplementowana przez Steve'a Russela na IBM 704:

Zgodnie z tym, co napisał Paul Graham w Hackers & Painters, s. 185, McCarthy powiedział: „Steve Russell powiedział, spójrz, dlaczego nie zaprogramuję tego evalu… i powiedziałem mu, ho, ho, mylisz teorię z praktyką, ta ocena jest przeznaczona do czytania, a nie do obliczeń. Ale poszedł naprzód i zrobił to. To znaczy, skompilował eval w moim artykule do kodu maszynowego IBM 704, naprawił błąd, a następnie ogłosił to jako interpreter Lispa, którym z pewnością był. Więc w tym momencie Lisp miał zasadniczo forma, jaką ma dzisiaj… ”

Więc Lisp został zreifikowany z abstrakcyjnej koncepcji do rzeczywistego języka programowania.  

Vivin Paliath
źródło
2
Wydaje się, że reifikacja istnieje w kontinuum w zależności od sytuacji. Podczas gdy abstrakcyjne lisp zostało zreifikowane w języku programowania, sam język programowania jest dość abstrakcyjną formą koncepcyjną komunikującą obliczenia, które muszą być dalej przekształcane w kod maszynowy, a ostatecznie na 1s i 0s, a następnie na sygnały elektryczne ... itd. Itd. Zatem reifikacja jest przeciwieństwem (dualnością) abstrakcji.
CMCDragonkai
25

Reifikacja

Reifikacja jest formą instancji. Kiedy reifikujesz pojęcie, bierzesz coś abstrakcyjnego i nadajesz mu konkret, tak jak podana definicja słownikowa.

Możesz zdecydować się na reifikację typu jako terminu zamieszkującego jakieś abstrakcyjne drzewo składniowe możliwych typów.

Możesz zreifikować wzorzec projektowy, wymyślając implementację ogólnego przeznaczenia w jakimś języku. Na przykład coś takiego

template<typename T> class Singleton {
    public:
        static T& Instance() {
            static T me;
            return me;
        }

    protected:
       virtual ~Singleton() {};
       Singleton() {};
}

reifikuje pojedynczy wzorzec projektowy jako szablon w C ++.

Możesz przekształcić pomysł Hoare na szybkie sortowanie w implementację w wybranym języku programowania. W tym duchu spędzam dużo czasu na przekształcaniu koncepcji z teorii kategorii do kodu Haskella.

Możesz reifikować język jako tłumacz dla tego języka. Pomysł Larry'ego Walla na język Perl został zreifikowany jako interpreter perla.

Te dane-zreifikować i próżniowe opakowania zreifikować terminy jak wykresy reprezentujące jak jest skonstruowany w pamięci z dzielenia.

Odbicie

Drugą stroną urzeczowienia jest refleksja , która bierze coś konkretnego i generuje abstrakcję, zwykle zapominając o niektórych szczegółach. Być może chcesz to zrobić, ponieważ abstrakcja jest prostsza lub w jakiś sposób oddaje istotę tego, o czym mówisz.

Odbicie systemu typów w Javie, C # itp. Przyjmuje konkretną klasę w języku programowania i zapewnia abstrakcyjną strukturę klasy, dając dostęp do listy elementów członkowskich, które zapewniają te klasy. Tutaj bierzemy konkretne pojęcie typu i generujemy z niego abstrakcyjny termin, który opisuje jego strukturę, jednocześnie odrzucając jakiekolwiek określone wartości.

Podobnie jak w przypadku przekształcania języka programowania w implementację, czasami możesz pójść w przeciwnym kierunku. Chociaż jest to ogólnie uważane za zły pomysł, możesz wziąć implementację i spróbować odzwierciedlić specyfikację języka na podstawie pożądanych właściwości jego zachowania. TeX został zaimplementowany jako pierwszy przez Knutha, bez specyfikacji. Każda specyfikacja TeX została odzwierciedlona w implementacji Knutha.

(Bardziej formalnie, jeśli postrzegasz refleksję jako zapominalski funktor, który przenosi cię z domeny konkretnej do domeny abstrakcyjnej, wówczas reifikacja jest najlepiej pozostawiona w połączeniu z refleksją).

Odbicie pakiet utrzymuję zapewnia zreifikować metodę, która przyjmuje termin i dające rodzaj, który reprezentuje go, a następnie odbić metodę, która pozwala wygenerować nowy termin. W tym przypadku domena „konkretna” to system typów, a domena abstrakcyjna to terminy.

Edward KMETT
źródło
21

Z Haskell Wiki :

„Ureifikować” coś to wziąć coś, co jest abstrakcyjne i traktować to jako materialne. Klasycznym przykładem jest sposób, w jaki starożytni przyjmowali abstrakcyjne pojęcia (np. „Zwycięstwo”) i przekształcali je w bóstwa (np. Nike, grecka bogini zwycięstwa).

Typ reified to wartość reprezentująca typ. Używanie typów reifikowanych zamiast typów rzeczywistych oznacza, że ​​możesz wykonywać na nich dowolne manipulacje, które możesz wykonywać na wartościach.

Kynth
źródło
15

Jednym z zastosowań, które przychodzą mi do głowy (jestem pewien, że są inne!) Jest zamiana klasy w słownik. Weźmy Eqzajęcia (zapominając /=na chwilę o operatorze):

class Eq a where
    (==) :: a -> a -> Bool

Jeśli zreifikujemy tę klasę, stanie się ona:

data EqDict a = EqDict (a -> a -> Bool)

które można skonstruować, skontrolować i tak dalej. Warto również zauważyć, że możesz mieć tylko jedną Eqinstancję na typ, ale wiele EqDictwartości. Ale automatyczna konstrukcja instancji (np. Uzyskiwanie równości dla list, gdy masz ją dla elementów) nie działa; będziesz musiał sam skonstruować EqDict [a]wartość.

Proces reifikacji jest tak prosty (w tym przypadku):

reify :: Eq a => EqDict a
reify = EqDict (==)

Funkcja korzystająca z Eqklasy może przekształcić coś takiego:

-- silly example, doesn't really do anything
findMatches :: Eq a => a -> [a] -> [a]
findMatches x ys = [ y | y <- ys, x == y ]

-- version using EqDict
findMatchesDict :: EqDict a -> a -> [a] -> [a]
findMatchesDict (EqDict f) x ys = [ y | y <- ys, f x y ]

Jeśli rozpakujesz EqDict i po prostu zdasz an a -> a -> Bool, otrzymasz ..Byfunkcje, like Data.List.nubByi friends - podobna sztuczka dla Ordpotencjalnych klientów Data.List.sortBy.

yatima2975
źródło
9

Nawet w kontekście Haskella termin ten jest używany bardzo szeroko. Pakiet reify Andy'ego Gilla pozwala na przyjmowanie struktur rekurencyjnych i przekształcanie ich w jawne wykresy. Post Sigpfe dotyczący kontynuacji opisuje przekształcenie pojęcia „reszty obliczeń” w wartość, którą można przekazać. Szablon Haskell ma funkcję reify (wykonywaną wraz z kodem TH w ogóle, w czasie kompilacji), która po podaniu nazwy wartości Haskell zwraca dostępne informacje o niej (gdzie został zadeklarowany, typ itp.).

Co łączy te wszystkie przypadki? Mówią o wzięciu czegoś, o czym możemy rozumować i o czym wiemy, ale nie możemy bezpośrednio programowo manipulować, i zmienić to w rzeczywistą wartość pierwszej klasy, którą możemy nazwać i przekazać tak jak każdą inną. I to jest generalnie intencja, którą ludzie chcą przekazać, używając tego słowa.

sclv
źródło
2

Wiem, że w RDF istnieje koncepcja reifikacji. Jak stwierdził Tim Bernes-Lee :

Reifikacja w tym kontekście oznacza wyrażenie czegoś w języku używającym tego języka, tak aby język mógł to uczynić.

Przypuszczam, że to trochę jak refleksja lub introspekcja. Mam nadzieję, że otrzymałeś tutaj dobre odpowiedzi!

M. Dudley
źródło