Jac*_*eja 6 dsl f# metaprogramming clojure
我正在尝试确定Clojure和F#用于创建DSL的设施.每个提供什么设施来创建和操纵DSL?
由于F#是静态类型的,这是否会使这项特定任务更加困难?在Clojure部分,我没有真正的经验,但已知所有LISP都非常适合元编程/ DSL.
我的问题不是打算在两种语言之间发动战争.如果我最近对这两个问题提出质疑是因为我认为两者都很棒,并且想要更多地了解这两者的具体情况.
在阅读了一些关于故意编程的日子之后,它让我重新燃起了对DSL和所有人的兴趣.
虽然我对F#有一些了解,但我还没有使用引文或类似的东西开发任何东西.我已经看到了基于歧视联盟的DSL的例子,这看起来很有趣.
您最终可以使用任何语言创建DSL.
使Clojure /其他Lisps特别独特且非常适合元编程的原因在于它们是同音的 - 也就是说,语言本身在同一语言的数据结构中自然表达.在Lisp中,您实际上是直接将代码编写为AST.
这非常强大 - 这意味着代码生成实际上等同于创建相对简单的数据结构.该语言为您提供了在编译时通过宏生成任意代码的工具.这有效地允许您"扩展语言"以支持您需要的任何特定DSL.
作为一个例子,我最近发现自己想要for在Clojure中使用命令式循环(对函数式编程纯粹主义者道歉,但有时你想要一个......).将此添加到该语言是一个5线程:
(defmacro for-loop [[sym init check change :as params] & steps]
`(loop [~sym ~init value# nil]
(if ~check
(let [new-value# (do ~@steps)] (recur ~change new-value#))
value#)))
Run Code Online (Sandbox Code Playgroud)
所以现在我能做到:
(for-loop [i 0 (< i 10) (inc i)]
(println i))
=> < prints numbers from 0..9 >
Run Code Online (Sandbox Code Playgroud)
这显然是一个简单的例子,但是应该很清楚,通过创建一组扩展到您想要的代码的短宏来生成新语言结构的能力使得构建DSL特别容易.
您可能会发现一些有趣的阅读/链接:
我无法谈论 Clojure,因为我没有使用过它,但我对 F# 中的 DSL 了解一些。F# 提供了两个主要的面向语言的编程功能(Don Syme 喜欢这样称呼它们):代码引用和计算表达式。
代码引用更接近 Lisp 等语言中的宏。它们允许您以编程方式生成表达式,然后可以执行该表达式。通过使用ReflectedDefinitionF# 表达式上的属性,您可以访问它们的 AST。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd233212.aspx 。
计算表达式类似于 Haskell 中的 do 表示法。编译器使用特殊语法将代码重写为对您定义的类型的调用。理想情况下,这种类型应该形成一个 monad。由于它们是伪装的 monad,因此它们应该允许您实现 DSL 的自定义语义。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd233182.aspx 。
IMO 计算表达式更适合在 F# 之上编写 DSL,而代码引用更适合转换或翻译等任务(例如 F# 到 JavaScript)。
除了这两个主要功能之外,您还可以使用该语言的其余部分。
当然,上面我只讨论了嵌入式领域特定语言。您可以加倍努力,将 fslex 和 fsyacc 用于独立 DSL。