mik*_*era 6 lisp dsl code-generation functional-programming clojure
我正在设计一个Clojure中的DSL,用于驱动代码生成器(在这种情况下用于程序图像合成 - clisk),并且无法计算出中间值的最佳表示.
最初DSL由返回一个或多个表单的函数组成,例如(说明性的)
(v+ 1.0 [1.0 'y])
=> ['(+ 1.0 1.0) '(+ 1.0 y)]
Run Code Online (Sandbox Code Playgroud)
然后可以组合这些函数以构建更大的代码块.
这很简单,结果表格可以直接输入代码生成器.然而,我现在已经确定了这种方法看起来有些弱点,例如,如果需要传递一些辅助数据(例如,无法以BufferedImages等形式编码的对象,对优化有用的元数据等).
我确信这是Lisp世界中一个已经解决的问题 - 这种DSL的最佳中间代表通常是什么?
无论何时你需要一个用于生成代码的中间表示,我脑海中最明显的一点是抽象语法树(AST).您的示例表示是列表,根据我的经验,它不像表单那样灵活.对于任何事情而言,除了琐碎的代码生成之外,我都不会在灌木丛中徘徊,只需要完整的AST表示.通过使用列表,您可以将更多工作推送到生成端,以解析类型和第一项所指的信息.转移到AST表示将为您提供更大的灵活性并使系统的更多分离,代价是解析方面的更多工作(或生成表单的函数的更多工作).生成方也将做更多的工作,但是这些组件中的许多组件可以解耦,因为它们的输入将更加结构化.
就AST应该是什么样子而言,我会复制Christophe Grand在他使用的地方的活跃 {:tag <tag name> :attrs <map of attrs> :content <some collection>}
或者什么是clojure脚本使用的,{:op <some operator> :children <some collection>}.
这使得相当普遍的,因为你可以定义窥视到任意的步行者:children并可以穿越任何结构没有清楚地知道什么对:op的或者:tag的是.
然后对于原子组件,您可以将其包装在一个映射中,并为其提供一些类型信息(关于DSL的语义),它与对象的实际类型无关.{:atom <the object> :type :background-image}.
在代码生成方面,当遇到一个原子时,你的代码可以随后调度:type,然后,如果你愿意,可以进一步调度对象的实际类型.从集合表单生成也很容易,发送到:op /:tag,然后与孩子一起重复.对于儿童使用的集合,我会详细阅读有关Google群组的讨论.他们的结论对我有启发意义.
https://groups.google.com/forum/#!topic/clojure-dev/vZLVKmKX0oc/discussion
总而言之,对于儿童,如果存在语义排序重要性,例如在if语句中,则使用地图{:conditional z :then y :else x}.如果它只是一个参数列表,那么你可以使用一个向量.