In quale area la macro di LISP è migliore della "capacità" di Ruby di creare DSL


21

Una delle cose che fa brillare Ruby è la capacità di creare meglio lingue specifiche del dominio, come

Sebbene si possano duplicare queste librerie in LISP tramite macro, penso che l'implementazione di Ruby sia più elegante. Tuttavia, penso che ci siano casi in cui la macro di LISP può essere migliore di quella di Ruby, anche se non riuscivo a pensarne una.

Quindi, in quale area la macro di LISP è migliore della "capacità" di Ruby di creare DSL?

aggiornare

L'ho chiesto perché i moderni linguaggi di programmazione si stanno avvicinando alla singolarità LISP , come

  • C ha un preprocessore di espansione macro , anche se molto primitivo e soggetto a errori
  • C # ha degli attributi, sebbene sia di sola lettura, esposto attraverso la riflessione
  • Python ha aggiunto Decorator, che può modificare il comportamento della funzione (e della classe per la versione 3.0), anche se sembra piuttosto limitato.
  • Ruby TMTOWTDI che rende elegante DSL, se viene applicata cura, ma in modo Ruby.

Mi chiedevo se la macro di LISP fosse applicabile solo a casi speciali e che le altre funzionalità del linguaggio di programmazione fossero abbastanza potenti da sollevare l'astrazione per affrontare le sfide odierne nello sviluppo del software.


4
Non sono sicuro del perché ci siano voti stretti su questo. Ho pensato che questo è il tipo di domanda che vogliamo ? Interessante, stimolante e la portata è definita abbastanza bene.
Tim Post

Prova a implementare qualcosa del genere in Ruby: meta-alternative.net/pfront.pdf
SK-logic

@Tim Post: Un problema è che questa non è una domanda facile a cui rispondere se non conosci bene sia Common Lisp che Ruby. Un altro è i riferimenti abbastanza ignoranti ad altre lingue, che possono infastidire i puristi: non esiste un linguaggio chiamato C / C ++, e la parte significativa di C ++ è il sistema modello e il suggerimento che il sistema macro di Common Lisp è applicabile solo a casi speciali. Fondamentalmente, è una buona domanda, ma è scritta male ed è difficile rispondere.
David Thornley,

@ David Thornley, ho aggiornato il post, in particolare su C \ C ++, e ho posto l'accento su C. Per quanto riguarda Common Lisp, ho sentito che, poiché altri linguaggi di programmazione hanno un'astrazione più elevata, la sua funzione macro è per casi speciali. Ho pubblicato la domanda, sperando che altri mi mostrino che la macro di CL non è per il caso speciale è ancora una funzionalità potente.
Onesimus Nessun impegno,

@OnesimusUnbound: Includerei davvero i modelli di C ++ nel tuo elenco di esempi di linguaggio, dal momento che sono almeno teoricamente capaci di qualsiasi calcolo che il sistema macro Lisp può fare. Per quanto riguarda le macro di Lisp, procurati un buon codice Common Lisp (c'è un sacco di codice Lisp F / OS là fuori) e cerca "defmacro" (potresti voler fare una ricerca senza distinzione tra maiuscole e minuscole). Probabilmente ne troverai molti. Considera che le macro sono più difficili delle funzioni per scrivere e ottenere correttamente, e ti renderai conto che devono essere generalmente utili.
David Thornley,

Risposte:


23

Leggi su Lisp e poi decidi tu stesso.

La mia sintesi è che Ruby è migliore nel fornire sintassi conveniente. Ma Lisp vince, a mani basse, alla capacità di creare nuove astrazioni, e quindi di stratificare l'astrazione sull'astrazione. Ma devi vedere Lisp in pratica per capire quel punto. Quindi il libro lo consiglia.


1
"Let Over Lambda" copre un terreno molto simile. Consigliata anche la lettura.
John R. Strohm,

But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.Ora so perché. . .
Onesimus Nessun impegno,

Non è un grosso problema fornire qualsiasi tipo di sintassi su Lisp. In effetti, molto più facile rispetto a Ruby, grazie alle macro dei lettori.
SK-logic,

1
@ SK-logic: True. Tuttavia, Lispers evita le macro dei lettori perché una volta che percorri quella strada non ti senti più un Lisp. In effetti alcune varianti di Lisp, come Clojure, riservano macro ai lettori per il progettista della lingua.
btilly

14

Le strutture di Ruby per la creazione di DSL non cambiano la natura della lingua. Le strutture di metaprogrammazione di Ruby sono intrinsecamente legate alla sintassi e alla semantica di Ruby e tutto ciò che scrivi deve essere deviato nel modello a oggetti di Ruby.

Contrastalo con Lisp (e Scheme, le cui strutture macro differiscono ), dove le macro operano sul programma astratto stesso. Poiché un programma Lisp è un valore Lisp, una macro è una funzione che mappa una sintassi essenzialmente arbitraria con un'altra.

In effetti, un Ruby DSL si sente ancora come Ruby, ma un Lisp DSL non deve sentirsi come Lisp.


6
+1: LOOP non si sente molto Lispy, come esempio di DSL.
Frank Shearar,

2

Le DSL di Ruby non sono affatto DSL, e odio assolutamente usarle perché la loro documentazione è chiara su come funzionano davvero. Prendiamo ad esempio ActiveRecord. Ti permette di "dichiarare" le associazioni tra i Modelli:

class Foo < ActiveRecord::Base
    has_one :bar
    has_one :baz
end

Ma la dichiaratività di questo "DSL" (come la dichiaratività della classstessa sintassi di Ruby ) è una bugia orribile che può essere esposta da chiunque capisca come funzionano effettivamente i "DSL" di Ruby:

class Foo < ActiveRecord::Base
    [:bar,:baz,:qux,:quux].each do |table|
        has_one table if i_feel_like_it?(table)
    end
    puts "Just for shits and giggles, and to show"
    puts "just how fucked up Ruby really is, we're gonna ask you"
    puts "which SQL table you want the Foo model to have an"
    puts "association with.\n"
    puts "Type the name of a table here: "
    has_one gets.chomp.to_sym
end

(Prova a fare qualcosa di simile a quello all'interno del corpo di una defclassforma Lisp !)

Non appena si dispone di codice come sopra nel vostro codice di base, tutti gli sviluppatori del progetto deve comprendere appieno come Rubino DSL in realtà il lavoro (non solo l'illusione creano) prima di poter mantenere il codice. La documentazione disponibile sarà completamente inutile, perché documenta solo l' uso idiomatico , che preserva l'illusione dichiarativa.

RSpec è anche peggio di quanto sopra, perché ha casi bizzarri che richiedono il debug di un lungo reverse engineering. (Ho trascorso un'intera giornata cercando di capire perché uno dei miei casi di test fosse saltato. Si è scoperto che RSpec esegue tutti i casi di test che hanno contesti dopo casi di test senza contesto, indipendentemente dall'ordine in cui compaiono nella sorgente , poiché il contextmetodo inserisce il blocco in una struttura di dati diversa da quella normalmente inserita.)

I DSL Lisp sono implementati da macro, che sono piccoli compilatori. I DSL che puoi creare in questo modo non sono semplici abusi della sintassi esistente di Lisp. Sono dei mini linguaggi reali che possono essere scritti per essere completamente senza soluzione di continuità, perché possono avere una propria grammatica. Ad esempio, la LOOPmacro di Lisp è molto più potente del eachmetodo di Ruby .

(So ​​che hai già accettato una risposta, ma non tutti coloro che leggono questo vorranno leggere interamente On On Lisp .)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.