27

三种 lispy 同音语言DylanJuliaSeph都离开了前导括号 - 因此 Common Lisp 中的假设函数调用如下所示:

(print hello world)

看起来像以下假设的函数调用

print(hello world)

在上面提到的三种语言中。

如果 Clojure 走这条路——它必须牺牲什么才能到达那里?

推理:除了 Clojure 中令人惊叹的惰性函数数据结构、改进的映射和序列语法、对并发的语言支持、JVM 平台、工具和令人敬畏的社区 - 它作为“LISP”的独特之处在于前括号给出了同音性,它给出了提供语法抽象的宏。

但是,如果您不需要前括号 - 为什么要有它们?我能想到的保留它们的唯一论据是

(1) 在emacs中重用工具支持

(2) 促使人们“用 LISP 思考”,而不是试图将其视为另一种程序语言)

4

9 回答 9

24

(归功于 andrew cooke 的回答,他提供了 Wheeler 和 Gloria 的“Readable Lisp S-expressions Project”的链接)

上面的链接是一个项目,旨在为所有基于 s 表达式的语言提供可读的语法,包括 Scheme 和 Clojure。结论是它是可以做到的:有一种方法可以让 Lisp 不带括号可读

基本上,David Wheeler 的项目所做的就是向类 Lisp 语言添加语法糖,以提供更现代的语法,同时不会破坏 Lisp 对特定领域语言的支持。这些增强功能是可选的并且向后兼容,因此您可以根据需要包含尽可能多或尽可能少的增强功能,并将它们与现有代码混合使用。

该项目定义了三种新的表达式类型:

  • 卷曲中缀表达式。 (+ 1 2 3)在您想使用任何数量的中缀运算符的每个地方都变为 {1 + 2 + 3} 。(如果内联表达式使用多个运算符,例如 {1 + 2 * 3} - 尽管 {1 + {2 * 3} } 按预期工作,则需要小心处理特殊情况)。
  • 新时代的表达。(fxy) 变成 f(xy)(要求函数名和它的参数之间没有空格)
  • 甜蜜的表情。打开和关闭括号可以替换为(可选)类似 python 的语义缩进。Sweet-expression 可以与传统的括号 s-expression 自由混合。

结果是与 Lisp 兼容但更具可读性的代码。新语法糖如何增强可读性的示例:

(define (gcd_ a b)
    (let (r (% b a))
        (if (= r 0) a (gcd_ r a))))

(define-macro (my-gcd)
    (apply gcd_ (args) 2))

变成:

define gcd_(a b)
    let r {b % a}
        if {r = 0} a gcd_(r a)

define-macro my-gcd()
    apply gcd_ (args) 2

请注意语法如何与宏兼容,这是以前旨在改进 Lisp 语法的项目的问题(如 Wheeler 和 Gloria 所述)。因为它只是糖,每个新表达式的最终形式是一个 s 表达式,在处理宏之前由语言阅读器转换 - 所以宏不需要任何特殊处理。因此,“可读 Lisp”项目保留了同音性,即允许 Lisp 将代码表示为语言中的数据的属性,这使得它成为一个强大的元编程环境。

于 2013-07-08T10:37:57.827 回答
23

仅将括号移动一个原子以进行函数调用并不足以满足任何人。人们会抱怨缺少中缀运算符、开始/结束块等。另外,您可能不得不在各种地方引入逗号/分隔符。

给他们这个,宏将更难正确编写(而且编写看起来和行为都很好的宏可能会更难与你当时引入的所有新语法)。而且宏不是一个可以忽略或使人更烦人的好功能;整个语言(像任何其他 Lisp 一样)都建立在它们之上。clojure.core 中的大多数“用户可见”内容,包括 let、def、defn 等都是宏。

于 2012-03-02T12:43:01.153 回答
14

编写宏将变得更加困难,因为结构将不再简单 您将需要另一种方法来编码表达式的开始和停止位置使用一些句法符号来标记表达式的开始和结束 您可以编写生成表达式的代码也许您可以通过添加类似 a(来标记表达式的开头来解决这个问题......

从一个完全不同的角度来看,非常值得观看这段视频,了解熟悉和容易之间的区别,使 lisps 语法更熟悉不会使人们更容易学习,并且如果它看起来很像它不是的东西,可能会产生误导。

即使您完全不同意,该视频也值得一小时。

于 2012-03-02T17:19:52.630 回答
13

你不需要牺牲任何东西。david Wheeler有一个经过深思熟虑的方法,它完全透明且向后兼容,完全支持宏等。

于 2012-03-08T22:29:53.747 回答
5

您将拥有 Mathematica。Mathematica 接受函数调用 as f[x, y, z],但是当您进一步研究它时,您会发现这f[x, y, z]实际上是一个列表的语法糖,其中Head(element 0) 是f并且Rest(elements 1 到 N) 是{x, y, z}。您可以从看起来很像 S 表达式的列表构造函数调用,并且可以将未评估的函数分解为列表(Hold防止评估,就像quote在 Lisp 中一样)。

Mathematica 和 Lisp/Scheme/Clojure 之间可能存在语义差异,但 Mathematica 的语法是一个演示,您可以将左括号移动一个原子,并且仍然可以合理地解释它,使用宏构建代码等。

语法很容易用预处理器转换(比语义容易得多)。您可能可以通过Clojure 的 LispReader 的一些巧妙子类化获得您想要的语法。甚至有一个项目试图通过用方括号替换它们来解决 Clojure 令人反感的括号。(令我惊讶的是,这被认为是一件大事。)

于 2014-01-31T16:59:10.543 回答
2

“代码就是数据”的理念使可靠的元编程成为可能。与语法复杂的 Perl / Ruby 相比,它们的元编程方法仅在非常有限的情况下才可靠。Lisp 元编程非常可靠,以至于语言的核心都依赖于它。其原因是代码和数据共享的统一语法(同音性属性)。S 表达式是实现这种一致性的方式。

也就是说,在 Clojure 中存在隐含括号可能的情况:

例如以下三个表达式是等价的:

  1. (第一(休息(休息 [1 2 3 4 5 6 7 8 9])))
  2. (-> [1 2 3 4 5 6 7 8 9] (rest) (rest) (first))
  3. (-> [1 2 3 4 5 6 7 8 9] 先休息休息)

请注意,在第三个中,-> 宏能够在这种情况下推断出括号,从而将它们排除在外。像这样的特殊情况有很多。一般来说,Clojure 的设计偏向于少括号。例如,请参阅在 cond 中省略括号的有争议的决定。Clojure 在这个选择上是非常有原则和一致的。

于 2012-03-08T15:36:47.567 回答
2

我曾经编写 C/C#/Java/Pascal 代码,所以我强调 Lisp 代码有点陌生。然而,这种感觉只持续了几个星期——在相当短的时间之后,Lisp 风格会感觉很自然,你会开始斥责其他语言的“不规则”语法:-)

Lisp 语法有一个很好的理由。前导括号通过以单一形式收集函数和构成其参数的表达式,使代码在逻辑上更易于解析和阅读。

当您操作代码/使用宏时,重要的是这些形式:这些是您所有代码的构建块。因此,将括号放在精确界定这些形式的位置从根本上说是有意义的,而不是任意将第一个元素留在形式之外。

于 2012-03-03T02:14:30.137 回答
1

有趣的是 -有另一种球拍语法

@foo{blah blah blah}

读作

(foo "blah blah blah")
于 2014-09-12T07:30:57.443 回答
0
Were Clojure to go down this path - what would it have to sacrifice to get there?

牺牲将通过创建 List of List 来编写代码的感觉/心理模式......或更技术上说“直接编写 AST”。

注意:正如其他答案中提到的,还有其他一些事情会被吓到。

于 2012-03-02T16:39:42.297 回答