Jedną z rzeczy, która sprawia, że Ruby świeci, jest możliwość lepszego tworzenia języków specyficznych dla domeny
Chociaż można duplikować te biblioteki w LISP za pomocą makr, myślę, że implementacja Ruby jest bardziej elegancka. Niemniej jednak myślę, że zdarzają się przypadki, że makro LISP może być lepsze niż Ruby, chociaż nie mogłem wymyślić żadnego z nich.
Więc w jakim obszarze makro LISP jest lepsze niż „zdolność” Ruby do tworzenia DSL, jeśli w ogóle?
aktualizacja
Poprosiłem o tym, ponieważ nowoczesne języki programowania są zbliża osobliwość LISP , jak
- C ma preprocesor ekspansji makr , choć bardzo prymitywny i podatny na błędy
- C # ma atrybuty, choć jest to tylko do odczytu, ujawnione przez odbicie
- Python dodał dekorator, który może modyfikować zachowanie funkcji (i klasy dla v 3.0), choć wydaje się dość ograniczony.
- Ruby TMTOWTDI, który tworzy elegancki DSL, jeśli zastosowano ostrożność, ale w sposób Ruby.
Zastanawiałem się, czy makro LISP ma zastosowanie tylko w szczególnych przypadkach i czy inne funkcje języka programowania są wystarczająco potężne, aby podnieść abstrakcję i sprostać dzisiejszym wyzwaniom związanym z tworzeniem oprogramowania.
Odpowiedzi:
Przeczytaj o Lisp, a następnie sam zdecyduj.
Podsumowując, Ruby jest lepszy w zapewnianiu wygodnej składni. Ale Lisp wygrywa bez użycia umiejętności tworzenia nowych abstrakcji, a następnie nakładania abstrakcji na abstrakty. Ale musisz zobaczyć Lisp w praktyce, aby zrozumieć ten punkt. Dlatego polecam książkę.
źródło
But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.
Teraz wiem dlaczego. . .Funkcje Rubiego do tworzenia DSL nie zmieniają charakteru języka. Funkcje metaprogramowania Ruby są nieodłącznie związane ze składnią i semantyką Ruby, a wszystko, co piszesz, musi zostać przeniesione do modelu obiektowego Ruby.
Porównaj to z Lisp (i Scheme, których funkcje makr różnią się ), gdzie makra działają na samym abstrakcyjnym programie. Ponieważ program Lisp jest wartością Lisp, makro jest funkcją odwzorowującą jedną zasadniczo dowolną składnię na inną.
W rzeczywistości Ruby DSL nadal czuje się jak Ruby, ale DSL Lisp nie musi czuć się jak Lisp.
źródło
DSL Ruby wcale nie są DSL i absolutnie nie znoszę ich używać, ponieważ ich dokumentacja kłamie na temat tego, jak naprawdę działają. Weźmy na przykład ActiveRecord. Pozwala „zadeklarować” powiązania między modelami:
Ale deklaratywność tej „DSL” (podobnie jak deklaratywność
class
samej składni Ruby ) jest okropnym kłamstwem, które może zostać ujawnione przez każdego, kto rozumie, jak faktycznie działają „DSL” Ruby:(Po prostu spróbuj zrobić coś zbliżonego do tego w ciele
defclass
formularza Lisp !)Gdy tylko w kodzie znajdziesz kod podobny do powyższego, każdy programista w projekcie musi w pełni zrozumieć, w jaki sposób faktycznie działa DSL Ruby (a nie tylko iluzję, którą tworzą), zanim będzie mógł zachować kod. Dostępna dokumentacja będzie całkowicie bezużyteczna, ponieważ dokumentują tylko idiomatyczne użycie, które zachowuje deklaratywną iluzję.
RSpec jest jeszcze gorszy od powyższego, ponieważ ma dziwne przypadki brzegowe, które wymagają obszernej inżynierii wstecznej do debugowania. (Cały dzień próbowałem dowiedzieć się, dlaczego jeden z moich przypadków testowych został pominięty. Okazało się, że RSpec wykonuje wszystkie przypadki testowe, które mają konteksty po przypadkach testowych bez kontekstu, niezależnie od kolejności, w jakiej występują w źródle , ponieważ
context
metoda umieszcza blok w innej strukturze danych niż normalnie.)Listy DSL Lisp są implementowane przez makra, które są małymi kompilatorami. Listy DSL, które możesz utworzyć w ten sposób, nie są zwykłym nadużyciem istniejącej składni Lisp. Są to prawdziwe mini-języki, które można napisać, aby były całkowicie płynne, ponieważ mogą mieć własną gramatykę. Na przykład
LOOP
makro Lispa jest znacznie potężniejsze niżeach
metoda Ruby .(Wiem, że już zaakceptowałeś odpowiedź, ale nie każdy, kto ją przeczyta, będzie chciał przeczytać całość On Lisp ).
źródło