将 Clojure 宏用于 DSL

发布于 2024-10-28 04:41:12 字数 635 浏览 5 评论 0 原文

我正在做一个 Clojure 项目,我经常发现自己为 DSL 编写 Clojure 宏,但我正在观看一个 Clojure 视频,介绍一家公司如何在实际工作中使用 Clojure,演讲者说在实际使用中,他们不会在他们的实际工作中使用宏。 DSL,它们只是使用宏来添加一点语法糖。这是否意味着我应该使用标准函数编写 DSL,然后在最后添加一些宏?

更新: 在阅读了对该问题的许多不同(且有趣)的回答后,我意识到答案并不像我最初想象的那么明确,原因有很多:

  1. 应用程序中有许多不同类型的 API(内部、外部) )

  2. API 的用户有多种类型(只想快速完成某件事的业务用户、Clojure 专家)

  3. 是否有宏可以隐藏样板代码?

我会离开并更深入地思考这个问题,但感谢您的回答,因为它们给了我很多思考。我还注意到 Paul Graham 的想法与 Christophe 视频相反,他认为宏应该成为代码库的很大一部分 (25%):

http://www.paulgraham.com/avg.html

I am working on a Clojure project and I often find myself writing Clojure macros for DSLs, but I was watching a Clojure video of how a company uses Clojure in their real work and the speaker said that in practical use they do not use macros for their DSLs, they only use macros to add a little syntactic sugar. Does this mean I should write my DSL in using standard functions and then add a few macros at the end?

Update:
After reading the many varied (and entertaining) responses to this question I have realized that the answer is not as clear cut as I first thought, for many reasons:

  1. There are many different types of API in an application (internal, external)

  2. There are many types of user of the API (business user who just wants to get something done fast, Clojure expert)

  3. Is there macro there to hide boiler plate code?

I will go away and think about the question more deeply, but thanks for your answers as they have given me lots to think about. Also I noticed that Paul Graham thinks the opposite of the Christophe video and thinks macros should be a large part of the codebase (25%):

http://www.paulgraham.com/avg.html

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

姜生凉生 2024-11-04 04:41:12

在某种程度上,我相信这取决于 DSL 的用途/目的。

如果您正在编写一个要在 Clojure 代码中使用的类似库的 DSL,并希望以函数方式使用它,那么我更喜欢函数而不是宏。函数对于 Clojure 用户来说“很好”,因为它们可以动态地组合成高阶函数等。例如,您正在编写一个函数式 Web 框架,如 Ring

如果您正在编写一个命令式 DSL,它将非常独立于其他 Clojure 代码使用,并且您已经决定绝对不需要高阶函数,那么用法将非常相似,您可以选择以最有意义的为准。例如,您可能正在创建某种业务规则引擎。

如果您正在编写需要生成高性能代码的专用 DSL,那么您可能会在大多数情况下希望使用宏,因为它们会在编译时进行扩展以实现最高效率。例如,您正在编写一些图形代码,需要扩展为完全正确的 OpenGL 调用序列……

To some extent I believe this depends on the use / purpose of your DSL.

If you are writing a library-like DSL to be used in Clojure code and want it to be used in a functional way, then I would prefer functions over macros. Functions are "nice" for Clojure users because they can be composed dynamically into higher order functions etc. For example, you are writing a functional web framework like Ring.

If you are writing a imperative DSL that will be used pretty independently of other Clojure code and you have decided that you definitely don't need higher order functions, then the usage will be pretty similar and you can chose whichever makes most sense. For example, you might be creating some kind of business rules engine.

If you are writing a specialised DSL that needs to produce highly performant code, then you will probably want to use macros most of the time since they will be expanded at compile time for maximum efficiency. For example, you're writing some graphics code that needs to expand to exactly the right sequence of OpenGL calls......

‖放下 2024-11-04 04:41:12

是的!

尽可能编写函数。当函数可以做到的时候,永远不要编写宏。如果您写入许多宏,您最终会得到一些更难扩展的东西。例如,宏不能被应用或传递。

Christophe Grand:(不是 = DSL 宏)

http://clojure.blip.tv/file/4522250/

Yes!

Write functions whenever possible. Never write a macro when a function will do. If you write to many macros you end up with somthing that is much harder to extend. Macros for example cant be applied or passed around.

Christophe Grand: (not= DSL macros)

http://clojure.blip.tv/file/4522250/

你怎么敢 2024-11-04 04:41:12

不!

不要害怕广泛使用宏。如有疑问,请务必编写宏。函数对于实现 DSL 来说效果较差——它们给运行时带来了负担,而宏则允许在编译时间内完成许多重量级计算。试想一下将嵌入式 Prolog 实现为解释器函数和将 Prolog 编译为某种形式的 WAM 的宏的区别。

并且不要听那些说“宏不能应用或传递”的人的说法,这种说法完全是稻草人。那些人提倡解释器而不是编译器,这简直是荒谬的。

关于如何使用宏实现 DSL 的一些技巧:

  • 分阶段进行。定义从 DSL 到底层 Clojure 的一长串语言。使每个转换尽可能简单 - 这样您就可以轻松维护和调试 DSL 编译器。
  • 准备一个 DSL 组件工具箱,您在实现 DSL 时将重用这些组件。它应该包括不同语义的目标语言(例如,无类型的 eager 函数 - 它是 Clojure 本身、无类型的惰性函数、一阶逻辑、类型化的命令式、Hindley-Millner 类型的 eager 函数、数据流等)。使用宏,无缝地组合所有目标语义的属性是微不足道的。
  • 维护一套编译器构建工具。它应该包括解析器生成器(即使您的 DSL 完全采用 S 表达式也是有用的)、术语重写引擎、模式匹配引擎、图上一些常见算法的实现(例如图着色)等。

No!

Don't be afraid of using macros extensively. Always write a macro when in doubt. Functions are inferior for implementing DSLs - they're taking the burden onto the runtime, whereas macros allows to do many heavyweight computations in a compilation time. Just think of a difference of implementing, say, an embedded Prolog as an interpreter function and as a macro which compiles Prolog into some form of a WAM.

And do not listen to those who say that "macros cant be applied or passed around", this argument is entirely a strawman. Those people are advocating interpreters over compilers, which is simply ridiculous.

A couple of tips on how to implement DSLs using macros:

  • Do it in stages. Define a long chain of languages from your DSL to the underlying Clojure. Keep each transform as simple as possible - this way you'd be able to easily maintain and debug your DSL compiler.
  • Prepare a toolbox of DSL components that you will reuse when implementing your DSLs. It should include target languages of different semantics (e.g., untyped eager functional - it is Clojure itself, untyped lazy functional, first order logic, typed imperative, Hindley-Millner typed eager functional, dataflow, etc.). With macros it is trivial to combine properties of all that target semantics seamlessly.
  • Maintain a set of compiler-building tools. It should include parser generators (useful even if your DSLs are entirely in S-expressions), term rewriting engines, pattern matching engines, implementations for some common algorithms on graphs (e.g., graph colouring), etc.
断念 2024-11-04 04:41:12

下面是 Haskell 中使用函数而不是宏的 DSL 示例:

http://contracts.scheming.org/

这是 Simon Peyton Jones 谈论此实现的视频:

http://ulf.wiger.net/weblog/2008/02/29/simon-peyton-jones-composition-contracts-an-adventure-in- Financial-engineering/

在开始实现您自己的语言之前,请利用 Clojure 和 FP 的特性。我认为 SK-logic 的提示可以很好地告诉您实现完整的语言需要什么。有时值得付出努力,但这种情况很少见。

Here's an example of a DSL in Haskell that uses functions rather than macros:

http://contracts.scheming.org/

Here is a video of Simon Peyton Jones giving a talk about this implementation:

http://ulf.wiger.net/weblog/2008/02/29/simon-peyton-jones-composing-contracts-an-adventure-in-financial-engineering/

Leverage the characteristics of Clojure and FP before going down the path of implementing your own language. I think SK-logic's tips give you a good indication of what is needed to implement a full blown language. There are times when it's worth the effort, but those are rare.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文