什么是代码即数据?我听说它比“代码为ascii字符”更好,但为什么呢?我个人觉得“代码即数据”的哲学实际上有点令人困惑。
我已经涉足了Scheme,但我从来没有真正理解过代码即数据的事情,我想知道它到底是什么意思?
发布于 2010-11-10 10:55:01
这意味着你写的程序代码也是可以被程序操纵的数据。使用一个简单的Scheme表达式,例如
(+ 3 (* 6 7))您可以将其视为一个数学表达式,当计算该表达式时,会产生一个值。但它也是一个包含三个元素的列表,即+、3和(* 6 7)。通过引用列表,
'(+ 3 (* 6 7))您告诉scheme将其视为后者,即只包含三个元素的列表。因此,您可以使用程序操作此列表,然后对其进行评估。它给你的力量是巨大的,当你“得到”这个想法时,有一些非常酷的把戏可以玩。
发布于 2010-11-10 17:13:45
代码即数据实际上只是硬币的一面。另一种是数据即代码。
可以在Lisp代码中嵌入任意数据,并动态加载和重新加载它,这使得它(数据)非常易于处理,因为它可以消除数据表示方式和代码工作方式之间的任何潜在阻抗不匹配。
让我给你举个例子。
假设您想要编写包含各种怪物类的某种类型的计算机游戏。基本上有两个选择:在编程语言中对怪物类进行建模,或者使用数据驱动的方法,其中类描述是从XML文件中读取的。
在编程语言中进行建模具有易用性和简单性的好处(这总是一件好事)。根据需要根据monster类指定自定义行为也很容易。最后,实现可能已经过了很好的优化。
另一方面,从数据文件加载所有内容要灵活得多。您可以在语言不支持的情况下执行多重继承;可以执行动态类型;可以在运行时加载和重新加载内容;可以使用简单的、直接的、特定于域的语法,等等。但是现在你需要为整个事情编写某种运行时环境,而指定行为意味着要么在数据文件和游戏代码之间拆分数据,要么嵌入脚本语言,这是另一层附带的复杂性。
或者您可以使用Lisp的方式:指定您自己的子语言,将其转换为代码并执行。如果您正在使用的编程语言具有足够的动态性和语法灵活性,那么您可以从使用数据驱动方法(因为代码就是数据)和在代码中保留所有内容的简单性(因为数据就是代码)中获得所有好处。
顺便说一句,这并不是特定于Lisp的。在Lisp和C++之间有不同程度的代码-数据等价灰色。例如,Ruby使在应用程序中嵌入数据比Python更容易,而Python则比Java更容易。数据即代码和代码即数据都是一个连续体,而不是非此即彼的问题。
发布于 2010-11-10 12:57:11
作为一名Lisp程序员,您要学会将程序源视为数据。它不再是静态文本,而是数据。在某些形式的Lisp中,程序本身就是被执行的数据结构。
然后所有的工具都以这种方式定位。Lisp不是一个文本宏处理器,而是一个宏系统,它将程序作为数据来处理。程序与文本之间的转换也有它的工具。
让我们考虑一下向量中添加两个元素:
(let ((v (vector 1 2 3)))
(+ (aref v 0)
(aref v 1)))这没有什么不寻常的。您可以编译并运行它。
但是你也可以这样做:
(let ((v (vector 1 2 3)))
(list '+
(list 'aref v 0)
(list 'aref v 1)))这将返回一个带有加号和两个子列表的列表。这些子列表具有符号aref,然后是v的数组值和索引值。
这意味着构建的程序不仅包含符号,还包含数据。数组实际上是子列表的一部分。所以你可以构造程序,这些程序是数据,可以包含任意数据。
然后EVAL将程序作为数据进行评估。
CL-USER 17 > (setf *print-circle* t)
=> T上面告诉我们,打印机应该打印循环数据结构,以便在回读时保留身份。
CL-USER 18 > (let ((v (vector 1 2 3)))
(list '+
(list 'aref v 0)
(list 'aref v 1)))
=> (+ (AREF #1=#(1 2 3) 0) (AREF #1# 1))现在让我们将数据作为Lisp程序进行求值:
CL-USER 19 > (EVAL (let ((v (vector 1 2 3)))
(list '+
(list 'aref v 0)
(list 'aref v 1))))
=> 3如果您的编译器希望文本作为源,可以构造这些文本,但它们永远不能直接引用数据。对于这些基于文本的源构建,已经开发了许多工具,但其中许多工具往往是分阶段工作的。在Lisp中,操纵数据的功能可以直接应用于操纵程序,并且该功能是直接内置的,是评估过程的一部分。
所以Lisp给了你额外的自由度和新的思考方式。
https://stackoverflow.com/questions/4140727
复制相似问题