6

I am trying to determine what facilities Clojure and F# have for creating DSLs. What facilities does each provide in order to create and manipulate DSLs?

As F# is statically typed, does this make it more difficult for this specific task? On the Clojure part I have no real experience but all LISPs are known to be great for metaprogramming/DSLs.

My question is not intended to make a war or something of the sort between both languages. If I'm making questions about the both lately is because I do think both are great and want to know more about the specifics of the two.

After reading some days about Intentional Programming, it has made me revive my interest in DSLs and all.

Although I have some knowledge of F# it's true I haven't yet developed anything using quotations or something like that. I've seen examples of DSLs based on discriminated unions which seem interesting.

4

2 回答 2

5

您最终可以用任何语言创建 DSL。

使 Clojure / 其他 Lisps 特别独特且非常适合元编程的原因在于它们是同音异形的——也就是说,语言本身以相同语言的数据结构自然地表达。在 Lisp 中,您有效地将代码直接编写为AST

这非常强大——这意味着代码生成实际上等同于创建一个相对简单的数据结构。该语言为您提供了在编译时通过宏生成任意代码的工具。这有效地允许您“扩展语言”以支持您需要的任何特定 DSL。

举个例子,我最近发现自己想要一个forClojure 中的命令式循环(向函数式编程纯粹主义者道歉,但有时你想要一个......)。将此添加到语言中的是 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#)))

所以现在我可以这样做:

(for-loop [i 0 (< i 10) (inc i)]
   (println i))
=> < prints numbers from 0..9 >

这显然是一个简单的例子,但希望清楚的是,通过创建一组简短的宏来生成新的语言结构,这些宏可以精确地扩展为您想要的代码,这使得构建 DSL 变得特别容易。

一些您可能会感兴趣的阅读/链接:

于 2012-06-01T10:19:33.740 回答
4

由于我没有使用过 Clojure,所以我不能谈论它,但我对 F# 中的 DSL 有所了解。F# 提供了两个主要的面向语言的编程特性(Don Syme 喜欢这样称呼它们):代码引用和计算表达式。

代码引用更接近于使用 Lisp 等语言中的宏所获得的内容。它们允许您以编程方式生成表达式,然后您可以执行这些表达式。通过使用ReflectedDefinitionF# 表达式的属性,您可以访问它们的 AST。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd233212.aspx 。

计算表达式类似于 Haskell 中的 do 表示法。编译器使用特殊语法将代码重写为对您定义的类型的调用。这种类型应该理想地形成一个单子。由于它们是伪装的 monad,它们应该允许您实现 DSL 的自定义语义。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd233182.aspx 。

IMO 计算表达式更适合在 F# 之上编写 DSL,而代码引用更适合转换或翻译等任务(例如 F# 到 JavaScript)。

除了这两个主要功能之外,您还可以使用其他语言。

当然,上面我一直在谈论嵌入式领域特定语言。您可以加倍努力,将 fslex 和 fsyacc 用于独立的 DSL。

于 2012-06-01T09:26:17.993 回答