Uso de macros Clojure para DSL
higher-order-functions (4)
¡No!
No tengas miedo de usar macros extensivamente. Siempre escriba una macro cuando tenga dudas. Las funciones son inferiores para implementar DSL: llevan la carga al tiempo de ejecución, mientras que las macros permiten hacer muchos cálculos pesados en un tiempo de compilación. Solo piense en la diferencia de implementar, por ejemplo, un Prolog incrustado como una función de intérprete y como una macro que compila Prolog en alguna forma de WAM.
Y no escuchen a los que dicen que "las macros no pueden aplicarse o transmitirse", este argumento es completamente falso. Esas personas están abogando por los intérpretes sobre los compiladores, lo cual es simplemente ridículo.
Un par de consejos sobre cómo implementar DSL usando macros:
- Hazlo por etapas. Defina una larga cadena de idiomas desde su DSL al Clojure subyacente. Mantenga cada transformación lo más simple posible, de esta manera podrá mantener y depurar fácilmente su compilador DSL.
- Prepare una caja de herramientas de componentes DSL que reutilizará cuando implemente sus DSL. Debe incluir lenguajes de destino de semántica diferente (por ejemplo, funcional ansioso no tipeado - es Clojure en sí, funcional perezoso no tipeado, lógica de primer orden, imperativo mecanografiado, Hindley-Millner entonado funcional, flujo de datos, etc.). Con las macros, es trivial combinar propiedades de todas las semánticas objetivo sin problemas.
- Mantener un conjunto de herramientas de compilación. Debe incluir generadores de analizadores (útiles incluso si sus DSL están completamente en expresiones S), motores de reescritura de términos, motores de coincidencia de patrones, implementaciones para algunos algoritmos comunes en gráficos (por ejemplo, coloreado de gráficos), etc.
Estoy trabajando en un proyecto Clojure y a menudo me encuentro escribiendo macros Clojure para DSL, pero estaba viendo un video de Clojure de cómo una empresa usa Clojure en su trabajo real y el orador dijo que en el uso práctico no usan macros para su DSL, solo usan macros para agregar un pequeño suger sintáctico. ¿Significa esto que debería escribir mi DSL usando funciones estándar y luego agregar algunas macros al final?
Actualización : Después de leer las muchas respuestas variadas (y entretenidas) a esta pregunta, me he dado cuenta de que la respuesta no es tan clara como pensé en un principio, por muchas razones:
Hay muchos tipos diferentes de API en una aplicación (interna, externa)
Hay muchos tipos de usuarios de la API (usuario de negocios que solo quiere hacer algo rápido, experto de Clojure)
¿Hay macro allí para ocultar el código de la placa de la caldera?
Me iré y pensaré en la cuestión más profundamente, pero gracias por sus respuestas ya que me han dado mucho en qué pensar. También noté que Paul Graham piensa lo contrario del video de Christophe y piensa que las macros deberían ser una gran parte de la base de código (25%):
¡Sí!
Escribir funciones siempre que sea posible. Nunca escriba una macro cuando funcionará una función. Si escribe en muchas macros terminará con algo que es mucho más difícil de extender. Las macros, por ejemplo, no se pueden aplicar ni transferir.
Christophe Grand: (no = macros DSL)
Aquí hay un ejemplo de DSL en Haskell que usa funciones en lugar de macros:
http://contracts.scheming.org/
Aquí hay un video de Simon Peyton Jones dando una charla sobre esta implementación:
Aproveche las características de Clojure y FP antes de seguir el camino de la implementación de su propio idioma. Creo que los consejos de SK-logic te dan una buena indicación de lo que se necesita para implementar un lenguaje completo. Hay momentos en los que vale la pena el esfuerzo, pero esos son raros.
Hasta cierto punto, creo que esto depende del uso / propósito de su DSL.
Si está escribiendo una DSL tipo biblioteca para usar en el código Clojure y desea que se use de manera funcional, entonces preferiría las funciones a las macros. Las funciones son "agradables" para los usuarios de Clojure porque se pueden componer dinámicamente en funciones de orden superior, etc. Por ejemplo, está escribiendo un marco web funcional como Ring .
Si está escribiendo un DSL imperativo que se usará bastante independientemente de otros códigos Clojure y ha decidido que definitivamente no necesita funciones de orden superior, entonces el uso será bastante similar y podrá elegir el que tenga más sentido. Por ejemplo, podría estar creando algún tipo de motor de reglas de negocio.
Si está escribiendo una DSL especializada que necesita producir código de alto rendimiento , entonces es probable que desee utilizar macros la mayor parte del tiempo, ya que se expandirán en el momento de la compilación para obtener la máxima eficacia. Por ejemplo, está escribiendo un código de gráficos que necesita expandirse exactamente a la secuencia correcta de llamadas OpenGL ......