2012-02-04由“homoiconicity”http://en.wikipedia.org/wiki/Homoiconicity赞助。
背景:我即将选择购买哪本关于Clojure的书 - "Clojure in Action"或(4月底传入)“Clojure Programming”(您可以通过{{3}阅读) ,一半页面可见)。令我印象深刻的是,在这两本书中,这种属性 - 同质性 - 得到了如此重视。
由于Clojure的根源是基于Lisp的,所以我提到O'Reilly Rough Cuts这真的很重要。好吧,我可以看到详细解释的宏,但我没有听到提到的重点。现在比较一下(引自“行动中的Clojure”)
这种同质性也是Clojure宏观系统成为可能的原因。
几乎看起来没有它,宏是不可能的。甚至维基百科声明(上面的链接)也更加平衡,但这些来源(*)都没有计算人为因素而支持英语语法。
如果我没有弄错的话,可以在C#(例如)中使用宏语法(类似于Lisp),只需要C#团队付出更多努力。但这是设计师团队的成本,而不是用户(?)。第二 - habbits很重要。如果在现实生活中你认为“a + b”,并且在计算机世界中你经常把它翻译成“+ ab”,那么生产力就会受到影响(当我从C ++仿函数转到C#lambdas时,我可以看到这一点。)
这个赞美,Clojure程序员几乎直接将程序编写为AST,让我感到害怕,因为阅读“由于直接用十六进制代码编写代码,不仅你学习十六进制系统,而且你更接近机器”。
总结一下 - 我喜欢元编程,我喜欢类似Lisp的宏(虽然我不是Lisper),但我在这里看到两件事 - 宏和同质性。第一个毫无疑问是伟大的,第二个 - 不是那么多(就我的理解而言),因为它使人类适合计算机需求,而且它应该是另一种方式。
同性恋真的对人类(语言的最终用户)有益吗?或者它实际上几乎只对语言设计者有益?非常欢迎例子!
或者以防我改写 - 假设给定的语言有Lisp-macros,“增加”同质性会提高最终用户的生产力吗? Expresiveness?还是相反?
(*)我不能百分百肯定,因为我只看到一小部分Clojure书籍,我不是在阅读它们,只是评估它们的购买。
谢谢大家的答案,可惜我只选择一个作为解决方案:-),这并不意味着我更少重视别人,这对我来说是最完整的。
答案 0 :(得分:10)
不,你不一定需要同质性来创建一个强大的,类似Lisp的宏系统。同质性只是使这样一个系统更容易使用;没有它,你需要另一种语法来表达宏在评估时产生的AST。在同性语言中,宏观系统感觉很自然,因为程序和元程序看起来是一样的。
答案 1 :(得分:9)
宏并不严格要求同源性(例如:C / C ++预处理器实现了编译时宏系统)。
然而,homoiconcity使宏 更有效且易于使用:
作为一个小例子,这里是一个宏,它为Clojure添加了一个Java / C#样式“for”循环。
(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#)))
;; Usage:
(for-loop [i 0 (< i 10) (inc i)]
(println i))
就是这样 - 一个新的语言结构添加在六行代码中。你可以清楚地看到同音性 - 整个“循环”形式只是一个引用的Clojure数据结构。 init,check和change参数也是传递给宏的homoiconic clojure数据结构,表示循环控制表达式。没有必要进行任何解析来支持我的新语法。
我认为用任何非同性语言简洁或简单地做这件事是非常困难的。
答案 2 :(得分:5)
同质性是一个定义不明确的概念。
Lisp的不同之处在于它具有源代码的数据表示,并且求值程序将其作为输入。将源代码作为数据处理很容易,因为Lisp的所有常用功能都适用。
它提供的内容:
宏是转换源代码的函数。因此,您只需要对源代码进行一些表示,并在编译语言的执行/编译/解释中执行此转换步骤。
Lisp的工作方式使其变得方便,因为源代码是一种数据结构,可以通过多种内置函数和工具进行操作。请注意,更复杂的转换(需要理解Lisp语言的语法)在Lisp中也不容易做到 - 虽然已经实现了工具(例如所谓的代码行者)。 / p>
还有一些Lisps具有语法,而不是基于s表达式。一个例子是RLISP,计算机代数系统 REDUCE 的实现语言。 RLISP也支持宏。
可以基于字符串和字符串操作定义类似的方案。您还可以根据某种AST定义宏系统。
具有此类宏的语言示例:
答案 3 :(得分:3)
想象一下,使用使用<% code %>
在python中使用嵌入式java的古老而笨拙的Web模板语言方法。
然后宏语言将是java,目标语言将是python。调用宏意味着转出<% code %>
模式。您甚至可以设计这样的系统来支持参数,字符串的eval等。这将是真正的丑陋(有点像旧的jsp或PHP代码)。
一个可怕的想法:一些jsp用户是否会发现这样的系统比lisp系统更舒服?如果宏/目标语言相同,这个怪物会改进吗?
当然可以做到。人们用C ++模板做了一些了不起的事情。 Jay Freeman用Ackermann编写了一个C ++程序编译时间和不变的运行时间来证明C ++模板可以做这样的事情(大概是因为Fibonacci的例子不会炸掉足够的编译器?)。
至于同性恋:它并不能解决所有问题。即使有它,也常常有一些尴尬:行情,准引号等。你需要一些在“这是宏代码”和“这是目标语言代码”之间切换的方法。这是语言设计者需要解决的固有问题。您可以考虑使用eval方法使用字符串的烦恼,而不是使用列表作为数据结构或程序代码的lispy语言。程序源有点像字符串。字符串是一个非常可怕的数据结构。字符串中的字符串甚至更糟。查找任何quine代码(最好是非lisp)。他们可以被认为是非常错误的同性恋。
答案 4 :(得分:2)
虽然您需要一种用于宏的语言,但它不需要与编写其余代码的语言相同。您只需要“iconicity”*,“homo”部分是可选的。
在Ocaml中,宏用另一种称为camlp4
的语言编写#load "pa_extend.cmo";
value gram = Grammar.gcreate (Plexer.gmake ());
value exp = Grammar.Entry.create gram "expression";
EXTEND
exp:
[ "SUM"
[ x = exp; "+"; y = exp -> Op "+" x y
| x = exp; "-"; y = exp -> Op "-" x y]
| "PROD"
[ x = exp; "*"; y = exp -> Op "*" x y
| x = exp; "/"; y = exp -> Op "/" x y]
| "ATOM"
[ x = INT -> Int (int_of_string x)
| x = LIDENT -> Var x
| "("; x = exp; ")" -> x ] ]
;
END;
它正在转换的语言如下所示:
let rec search ?(x=0) ?(y=0) f accu = match x, y with
9, y -> search ~x:0 ~y:(y+1) f accu (* Next row *)
| 0, 9 -> f accu (* Found a solution *)
| x, y ->
if m.(y).[x] <> '0' then search ~x:(x+1) ~y f accu else
fold (fun accu n ->
let n = Char.chr (n + 48) in
if invalid x y n then accu else
(m.(y).[x] <- n;
let accu = search ~x:(x+1) ~y f accu in
m.(y).[x] <- '0';
accu)) accu 1 10
正如您所看到的,Ocaml中没有同质性,并且它具有高度发展的宏(类似)系统。