Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lisp/Clojure DSL的中间表示_Clojure_Functional Programming_Lisp_Code Generation_Dsl - Fatal编程技术网

Lisp/Clojure DSL的中间表示

Lisp/Clojure DSL的中间表示,clojure,functional-programming,lisp,code-generation,dsl,Clojure,Functional Programming,Lisp,Code Generation,Dsl,我正在Clojure中设计一个DSL,用于驱动一个代码生成器(在本例中用于程序图像合成),但我很难找到中间值的最佳表示形式 最初DSL由返回一个或多个表单的函数组成,例如(说明性) 然后可以组合这些函数来构建更大的代码块 这很简单,生成的表单可以直接输入代码生成器。但是,我现在已经确定了这种方法的一些弱点,例如,如果需要传递一些辅助数据(例如,无法以缓冲区图像、用于优化的元数据等形式编码的对象) 我确信这在Lisp世界中是一个已解决的问题-对于这种DSL,什么通常是最好的中间表示形式?我想我不明

我正在Clojure中设计一个DSL,用于驱动一个代码生成器(在本例中用于程序图像合成),但我很难找到中间值的最佳表示形式

最初DSL由返回一个或多个表单的函数组成,例如(说明性)

然后可以组合这些函数来构建更大的代码块

这很简单,生成的表单可以直接输入代码生成器。但是,我现在已经确定了这种方法的一些弱点,例如,如果需要传递一些辅助数据(例如,无法以缓冲区图像、用于优化的元数据等形式编码的对象)


我确信这在Lisp世界中是一个已解决的问题-对于这种DSL,什么通常是最好的中间表示形式?

我想我不明白。我自己只会使用列表或结构

在Lisp中,列表可以包含任何内容。我应该说,CONS单元格可以指向任何东西,因此列表可以包含任何东西。几乎任何其他数据结构(结构、数组、映射等)都可以

现在,这些结构不能通过打印进行渲染,也不能通过读取进行渲染,但这并不意味着它们不能被存储和操作


你有什么理由需要将这种表述外部化吗?

这不是一个真正的答案,因为我不知道Clojure在这方面是如何工作的,但在CL中,有专门为这种情况设计的读卡器宏:即,您将定义用于打印不可打印对象的函数+一个读卡器宏,该读卡器宏按照您打印对象的方式读取对象。要定义对象的打印方式,您需要定义一个新方法
print object
,该方法专门用于所需对象的类型,并
set macro character
向可读表添加一个函数,该函数知道如何读取设计的对象


有很多事情需要注意,但是一些通常像定时器炸弹的情况是,当对象被允许递归引用自己时,在这种情况下,打印需要考虑先前打印的对象。

随时需要一个中间代码来表示代码,我想到的最明显的事情是抽象语法树(AST)。您的示例表示是列表,根据我的经验,列表并不像表单那样灵活。除了简单的代码生成之外,我不会拐弯抹角,只使用一个完整的AST表示。通过使用列表,您可以将更多的工作推到生成端,以解析出诸如类型和第一项的含义之类的信息。迁移到AST表示将为您提供更大的灵活性,并使系统的更多部分解耦,但代价是来自解析方面的更多工作(或来自生成表单的函数的更多工作)。发电侧也将做更多的工作,但这些组件中的许多可以解耦,因为它们的输入将更加结构化

至于AST应该是什么样子,我会复制Christophe Grand的enlive,他在其中使用了
{:tag:attrs:content}

或者clojure脚本使用什么,
{:op:children}

这使得它非常通用,因为您可以定义任意漫游者,它们可以窥视
:children
,并且可以遍历任何结构,而不确切知道
:op
:tag
是什么

然后,对于原子组件,您可以将其包装在一个映射中,并为其提供一些独立于对象实际类型的类型信息(关于DSL的语义)<代码>{:atom:type:background image}

在代码生成方面,当遇到atom时,您的代码可以在
:type
上分派,然后,如果需要,可以在对象的实际类型上进一步分派。从集合表单生成也很容易,在:op/:tag上分派,然后和子对象一起重复。关于儿童收藏的内容,我读了更多关于谷歌群组的讨论。他们的结论对我很有启发


总之,对于孩子们来说,如果在if语句中存在语义排序重要性,那么使用map
{:conditional z:then y:else x}
。如果它只是一个参数列表,那么你可以使用一个向量。

最终我想使用诸如
(eval`(fn[x y z]~form to compile))之类的东西编译表单。
-但这不适用于嵌入式对象(请参阅)
(v+ 1.0 [1.0 'y])
=> ['(+ 1.0 1.0) '(+ 1.0 y)]