17

作为 Lisp 的新手,我想知道 Lisp 语法是否可以“固定”?

有人说 Lisp 中的语法是其最大的优势之一。我不太明白这一点。

难道不能用空格、换行和缩进的组合来替换“明显的”括号吗?就像在 Python 中一样?

在我看来,括号是 Lisp 代码中最常用的字符。我想知道这是否属实 - 但如果是这样,这不是一个建议,语法中有一些冗余吗?

这个问题是否有一些简单的答案 - 为什么有这么多括号?

例如:

(defun factorial (x)
    (if (= x 0)
        1
        (* x 
           (factorial (- x 1)))))

为什么不:

defun factorial (x)
  if (= x 0)
    1
    * x
      factorial
        - x 1

例如,在行尾关闭括号,并始终在新行中打开它们。只有 1 是模棱两可的——它是 1 还是 (1)——但我们可以引入一个例外——单个标记没有“列出”。

这能行吗?

编辑:

谢谢你们!我现在看到lispin网站上有一些链接

4

16 回答 16

31

一旦你写了几个宏,你就会改变主意。

于 2009-03-13T22:10:27.097 回答
28

它已经完成了很多次(一个 < 20 行的预处理器会创造奇迹)。但是让它们显式化也有一个优势。它推动了代码和数据之间的并行性,并在某种程度上让你摆脱了那种让你觉得它们很烦人的想法。

您可以(对于一个类似的示例)采用面向对象的语言并将所有方法的语法分组删除到类中(因此它们实际上变成了重载函数)。这会让你更多地看待它,就像你看一种直接的命令式语言一样,但也会丢失一些东西。

当您查看 lisp 时,您应该认为“一切都是列表。Ommm”

(好吧,好吧,“Ommm”是可选的)。

于 2009-03-13T18:17:52.633 回答
20

“也许这个过程应该被视为 Lisp 黑客的一种仪式。”

——斯蒂尔和加布里埃尔,“Lisp 的演变”,1993

于 2009-03-14T03:55:12.527 回答
12

您的建议似乎已在Lispin中实施

编辑: sindikat在下面的评论中指出该链接不再有效。这是 Web 存档中该站点的最后一个有效版本:http ://wayback.archive.org/web/20080517144846id_/http://www.lispin.org/

于 2009-03-13T18:10:12.183 回答
9

有几次我比较了 Lisp 代码和其他语言的等效代码。Lisp 代码有更多的括号,但如果你计算其他语言中的所有分组字符 []{}(),Lisp 的括号比所有这些都少。它不是更冗长:它更一致!

从这个角度来看,“问题”只是 Lisp 对所有内容都使用一种类型的构造(列表)。这是它的宏、它的对象系统、它的几个最强大的循环结构等等的基础。你所看到的轻微风格问题(括号看起来更酷吗?可能)实际上是语言能力的标志。

也就是说,Lisp 就是为程序员提供权力。如果您愿意,可以编写您自己的方言来执行此操作。Lisp(不像我可以提到的一些语言!)完全是关于程序员的能力,所以使用它。如果你能让它发挥作用,也许它会起飞。我不认为它会,但没有什么可以阻止你尝试,无论哪种方式你都会学到很多东西。

于 2009-03-14T04:02:21.637 回答
6

lisp“语法”的要点是它不存在。s 表达式是一棵身份树,其中树结构由括号(缩进)表示。值得注意的是,sexps 只是一种低级表示,但人们最终更喜欢它并继续使用它。

表达式对执行引擎的意义在 lisp 中非常灵活,而且它也是上下文敏感的。

在其他语言中,上下文敏感性的级别要低得多,并且可以用来构建自己的抽象的构建块集的自由扩展性要小得多。因此,表示少数给定结构的特殊语法很适合图片。

在 lisp 中,我可以更改所有内容的含义,即使是以上下文相关的方式。为一些预定义的构造使用特殊语法会很愚蠢,因为我最终可能会使用我自己的“if”或我自己的专门闭包等。如果我的新“if”需要 4 个参数怎么办(例如,将某些 if 分组计划并告诉一些小组在某些情况下总是失败或成功)?我应该如何扩展预定义的“if”的语法?求助于 AST(sexps)要容易得多,但是为什么还要使用特殊的语法呢?

还要注意,使用像 emacs 这样的编辑器可以很容易地以结构化的方式编辑这样的树。例如,有一个键来转置树中的两个节点对于交换变量声明和交换程序块中的两个语句同样有用(提示:这就是“额外”括号在 let、cond 等中有用的原因)。

所以,这就是为什么lisp 的非语法如此吸引许多习惯于扩展语言而不是弯曲问题以适应一组预定义工具的人的原因......但这并不意味着语法糖不用于用户给定的构造!

我们使用的用户定义语法的一些示例:

  • cl-syntax-sugar - 最显着的扩展是[]用于您不想命名闭包变量的小闭包的括号
  • cl-quasi-quote - 最值得注意的是<xml >在 lisp 代码中内联 xhtml 生成的语法(请注意,此语法由用户库提供,并且可以以上下文相关的方式启用)
于 2009-03-14T20:06:39.097 回答
5

它可以工作。它叫迪伦

于 2009-03-13T18:10:28.500 回答
5

即使是 Lisp 语言家族的倡导者Paul Graham也从他自己的方言Arc中删除了一些括号:

Lisp 黑客注意事项:如果你习惯了传统的 Lisp cond运算符,那么这个 if 相当于同样的事情,但括号更少。例如

(cond (a b)
      (c d)
      (t e))

变成

(if a b
    c d
    e)

(来自弧教程

于 2009-03-13T22:19:44.830 回答
3

有两种人™:通过大脑中内置的堆栈机处理信息的人,以及以大块或块形式消费信息的人。这些群体互不相容;他们读不同的书,有不同的写作风格,最重要的是,他们用不同的编程语言编写代码。我属于第二类;但是,我认识第一组的许多程序员。

对于第一类人来说,嵌套从句和从句绝对没有错;他们自然地掌握递归;他们慢慢地看代码,逐句逐句地查看代码,大脑中的堆栈机器不断地在潜意识层面计算大括号和括号。Lisp 语法对他们来说很自然。见鬼,他们可能发明了堆栈机器和 Forth 语言。但是给他们看,比如说,Python(哦,不!),他们会无助地瞥一眼代码,无法理解为什么这些愚蠢的代码块是打开的,没有匹配的结束语句。

对于我们第二组的穷人来说,除了将代码语句组合成块,并在视觉上缩进它们之外别无选择。我们看着充满代码的屏幕,首先注意到大规模的结构,然后是单独的函数或方法,然后是这些方法中的语句组,然后是行和语句,从上到下。我们不能线性思考;我们需要视觉边界和干净的缩进策略。因此,我们不能屈从于使用 Lisp。对我们来说,这是一堆不规则的关键字和愚蠢的括号。

大多数编程语言都兼容这两种思维方式(那些“块”是有原因的)。值得注意的例外是 Lisp 和 Forth,它们只属于第一组,而 Python 只属于第二组。如果你属于第二类,我认为你不需要让 Lisp 适应你的思维方式。如果您仍然需要函数式语言,请尝试 Haskell。它是一种功能性语言,专为以块而不是堆栈思考的人设计。

于 2009-03-13T18:34:18.333 回答
1

要回答为什么的问题:

据我所知,它的主要用途是可读性,以便查看您的代码的人可以更轻松地破译它。

希望能帮助到你。

于 2009-03-13T18:15:21.843 回答
1

通过链接阅读,我发现了这个 -缩进敏感语法- 还有一个 Guile 模块,它实现了这种语法,所以可以直接尝试。

可以在这里找到一个非常有前途的 Lisp 方言(Arc) 。(我想应该先用一些真实的代码看看感觉如何)

于 2009-03-14T00:57:44.467 回答
1

我个人对此的看法是:不要使用换行符和缩进作为“隐式”分隔符(我也不喜欢按运算符优先级进行隐式分组,但这是一个不同的主题,尽管相关)。

示例:这是有效的 Python 吗?它是否符合您的预期?

if foo < 0 :
    bar
  else :
    baz
quuz

我有一个小建议:我们可以使用预处理器自动缩进 Python 代码,方法是在代码中添加特殊字符,告诉它语句的开始和结束位置。括号怎么样?

于 2009-03-16T01:34:29.190 回答
1

你可以看看 Clojure。更少的括号,但更多的语法要记住。

于 2009-03-21T18:11:10.673 回答
1

我已经尝试并编写了几个依赖缩进的语法。最好的结果是整个语法改变了它的本质,因此语言已经从一种转向另一种。好的基于缩进的语法不再接近 lisp。

为缩进赋予句法意义的麻烦并不是从白痴和 \t 与空格的辩论中产生的。标记化既不是问题,因为阅读换行符和空格不应该比其他任何事情更难。最困难的事情是确定缩进在它出现的位置应该意味着什么,以及如何在不为语言制作过于复杂的语法的情况下为其添加含义。

当您通过一些巧妙的编程最大限度地减少括号的数量时,我开始考虑原始的 lisp 样式语法毕竟更好。这可以做到,在当前的 lisp 实现中不是那么容易,但在未来的 lisp 实现中可以更容易地做到。当您只需要标记几个规则并且几乎不需要解析时,解析起来既快速又简单。

于 2009-10-23T18:14:18.473 回答
1

这个线程很旧,但我决定贡献,因为我创建了一个非常相似的阅读器系统

编辑:一些使用示例:

!defun 事实 (n)
  if (zerop n)
    1
    * n
      事实
        (1-n)
!defun 事实 !n
  如果 !zerop n
    1
    !* n !fact !1- n

有关更多信息,请查看项目主页。

于 2012-10-05T11:25:59.853 回答
1

有一个备用的 Racket Syntax

@foo{blah blah blah}

读作

(foo "blah blah blah")
于 2014-09-12T07:29:30.967 回答