¿En qué área es mejor la macro de LISP que la "habilidad" de Ruby para crear DSL

21

Una de las cosas que hace brillar a Ruby es la capacidad de crear mejores lenguajes específicos de dominio, como

Aunque uno puede duplicar estas bibliotecas en LISP a través de macro, creo que la implementación de Ruby es más elegante. No obstante, creo que hay casos en que la macro de LISP puede ser mejor que la de Ruby, aunque no se me ocurre ninguno.

Entonces, ¿en qué área es mejor la macro de LISP que la "capacidad" de Ruby para crear DSL, si la hay?

actualizar

He preguntado esto porque los lenguajes de programación modernos se están acercando a la singularidad de LISP , como

  • C obtuvo un preprocesador de expansión macro , aunque muy primitivo y propenso a errores
  • C # tiene atributos, aunque este es de solo lectura, expuesto a través de la reflexión
  • Python agregó decorador, que puede modificar el comportamiento de la función (y la clase para v 3.0), aunque se siente bastante limitado.
  • Ruby TMTOWTDI que hace DSL elegante, si se aplica el cuidado, pero de manera Ruby.

Me preguntaba si la macro de LISP solo es aplicable a casos especiales y si las otras características del lenguaje de programación son lo suficientemente potentes como para aumentar la abstracción para enfrentar los desafíos actuales en el desarrollo de software.

Onésimo Sin consolidar
fuente
44
No estoy muy seguro de por qué hay votos cerrados sobre esto. ¿Pensé que este es el tipo de pregunta que queremos ? Interesante, estimulante y el alcance se define bastante bien.
Tim Post
Intente implementar algo como esto en Ruby: meta-alternative.net/pfront.pdf
SK-logic
@Tim Post: Un problema es que esta realmente no es una pregunta fácil de responder a menos que conozcas bien a Common Lisp y Ruby. Otro son las referencias bastante ignorantes a otros lenguajes, que pueden molestar a los puristas: no existe un lenguaje llamado C / C ++, y la parte importante de C ++ es el sistema de plantillas, y la sugerencia de que el sistema macro de Common Lisp solo es aplicable a casos especiales. Fundamentalmente, es una buena pregunta, pero está mal escrita y es difícil de responder.
David Thornley
@David Thornley, he actualizado la publicación, particularmente en C \ C ++, y pongo énfasis en C. En cuanto a Common Lisp, sentí que, dado que otros lenguajes de programación tienen una mayor abstracción, su función macro es para casos especiales. Publiqué la pregunta, esperando que otros me muestren que la macro de CL no es para un caso especial, todavía es una característica poderosa.
OnesimusUnbound
@OnesimusUnbound: Realmente incluiría las plantillas de C ++ en su lista de ejemplos de lenguaje, ya que son al menos teóricamente capaces de cualquier cálculo que pueda hacer el sistema macro Lisp. En lo que respecta a las macros de Lisp, obtenga un buen código Common Lisp (hay un montón de código Lisp F / OS) y busque "defmacro" (es posible que desee hacer una búsqueda que no distinga entre mayúsculas y minúsculas). Probablemente encontrarás muchos de ellos. Tenga en cuenta que las macros son más difíciles que las funciones de escribir y acertar, y se dará cuenta de que tienen que ser generalmente útiles.
David Thornley

Respuestas:

23

Lee en Lisp y luego decide por ti mismo.

Mi resumen es que Ruby es mejor para proporcionar una sintaxis conveniente. Pero Lisp gana, sin lugar a dudas, en la capacidad de crear nuevas abstracciones, y luego en capas de abstracción sobre abstracción. Pero necesita ver a Lisp en la práctica para comprender ese punto. De ahí el libro lo recomiendo.

btilly
fuente
1
"Let Over Lambda" cubre un terreno muy similar. También se recomienda leer.
John R. Strohm
But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.Ahora se porque. . .
OnesimusUnbound
No es un gran problema proporcionar ningún tipo de sintaxis sobre Lisp. De hecho, mucho más fácil que con Ruby, gracias a las macros del lector.
SK-logic
1
@ SK-logic: cierto. Sin embargo, los Lispers evitan las macros de los lectores porque una vez que sigues esa ruta ya no se siente como un Lisp. De hecho, algunas variantes de Lisp, como Clojure, reservan macros de lector para el diseñador de idiomas.
btilly
14

Las instalaciones de Ruby para la creación de DSL no cambian la naturaleza del lenguaje. Las instalaciones de metaprogramación de Ruby están inherentemente ligadas a la sintaxis y la semántica de Ruby, y lo que sea que escriba debe derivarse al modelo de objetos de Ruby.

Compare eso con Lisp (y Scheme, cuyas instalaciones macro difieren ), donde las macros operan en el programa abstracto en sí. Debido a que un programa Lisp es un valor Lisp, una macro es una función que asigna una sintaxis esencialmente arbitraria a otra.

Efectivamente, un DSL Ruby todavía se siente como Ruby, pero un DSL Lisp no tiene que sentirse como Lisp.

Jon Purdy
fuente
66
+1: LOOP no se siente muy Lispy, como un ejemplo de DSL.
Frank Shearar
2

Los DSL de Ruby no son DSL en absoluto, y odio absolutamente usarlos porque su documentación carece de cómo funcionan realmente. Tomemos ActiveRecord por ejemplo. Le permite "declarar" asociaciones entre modelos:

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

Pero la declaración de este "DSL" (como la declaración de la classsintaxis de Ruby en sí) es una mentira horrible que puede ser expuesta por cualquiera que entienda cómo funcionan realmente los "DSL" de 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

(¡Solo intenta hacer algo parecido a eso dentro del cuerpo de un defclassformulario Lisp !)

Tan pronto como tenga un código como el anterior en su base de código, cada desarrollador en el proyecto debe comprender completamente cómo funcionan realmente las DSL de Ruby (no solo la ilusión que crean) antes de que puedan mantener el código. La documentación disponible será completamente inútil, ya que solo documentan el uso idiomático , que preserva la ilusión declarativa.

RSpec es incluso peor que lo anterior, porque tiene casos extremos extraños que requieren una extensa ingeniería inversa para depurar. (Pasé todo un día tratando de averiguar por qué se saltaba uno de mis casos de prueba. Resultó que RSpec ejecuta todos los casos de prueba que tienen contextos después de los casos de prueba sin contexto, independientemente del orden en que aparecen en la fuente , porque el contextmétodo coloca su bloque en una estructura de datos diferente de la que normalmente entraría).

Los DSL de Lisp son implementados por macros, que son pequeños compiladores. Las DSL que puede crear de esta manera no son meros abusos de la sintaxis existente de Lisp. Son mini idiomas reales que se pueden escribir para que sean completamente fluidos, porque pueden tener su propia gramática. Por ejemplo, la LOOPmacro de Lisp es mucho más poderosa que el eachmétodo de Ruby .

(Sé que ya has aceptado una respuesta, pero no todos los que lean esto querrán leer la totalidad de On Lisp ).

Tirar cuenta
fuente