【问题标题】:Clojure vs other Lisps [closed]Clojure 与其他 Lisp [关闭]
【发布时间】:2011-08-25 21:13:24
【问题描述】:

我的问题的意图是不是发起一场激烈的战争,而是要确定每种语言在什么情况下是“完成这项工作的最佳工具”。

我已经阅读了几本关于 Clojure 的书籍(Programming ClojurePractical ClojureThe Joy of ClojureClojure in Action 的曼宁抢先体验版),我认为它是一门很棒的语言。我目前正在阅读Let Over Lambda,它主要处理 Common Lisp 宏,而且它也是一种非常有趣的语言。

不是 Lisp 专家(更像是一个新手),但是这个语言家族让我着迷,就像函数式编程一样。

Clojure 的优点(以及“其他”的缺点):

  • 在 JVM 上运行。

    • JVM 是一个非常稳定的高性能语言环境,非常符合 Sun 的“一次编写,[几乎] 随处运行”的梦想。我可以在我的 Macbook Pro 上编写代码,将其编译成可执行的 JAR 文件,然后在 Linux 和 Microsoft Windows 上运行它,几乎不需要额外的测试。

    • (Hotspot 和其他)JVM 支持高质量的垃圾收集和非常高性能的即时编译和优化。就在几年前,我用 C 编写了所有必须快速运行的东西,现在我毫不犹豫地用 Java 编写了。

    • 标准、简单、多线程模型。 Common Lisp 有标准的多线程包吗?

    • []{}#{} 打破所有这些括号的单调,尽管 Common Lisp 专家可能会告诉我,使用阅读器宏,您可以将它们添加到 CL。

Clojure 的缺点

  • 在 JVM 上运行。
    • 没有尾递归或延续。 Common Lisp 是否支持延续?我相信,Scheme 需要同时支持两者。

其他方法的优点(尤其是 Common Lisp)(以及 Clojure 的缺点):

  • 用户可定义的阅读器宏。

  • 其他优势?

想法?其他区别?

【问题讨论】:

  • 我个人喜欢一种括号;)看起来像“更干净”的代码
  • 从我读到的你的优点列表中,我想你可能也喜欢 Erlang www.erlang.org
  • Clojure 通过“recur”特殊形式支持显式尾递归。如果您明确要求,这使您能够获得尾递归的所有好处(唯一的例外是它目前不支持多个函数之间的相互尾递归)。
  • Clojure 也支持延续,至少在“延续传递风格”的意义上。你是对的,它没有一流的延续。见stackoverflow.com/questions/1173133/continuations-in-clojure
  • @mikera:一个函数的尾递归。两个相互调用的函数必须通过“蹦床”来完成,这有点笨拙(但以自己的方式优雅:-))。

标签: clojure comparison lisp scheme common-lisp


【解决方案1】:

我个人喜欢 Clojure 而不是其他 Lisps 的原因列表(p.s. 我仍然认为所有 Lisps 都很棒!):

  • 在 JVM 上运行 - 因此可以自动访问 JVM 本身的奇妙工程(高级垃圾收集算法、HotSpot JIT 优化等)

  • 非常好的 Java 互操作性 - 提供与 Java/JVM 语言生态系统中大量库的兼容性。我使用 Clojure 作为一种“胶水”语言来连接不同的 Java 库,效果很好。由于我还开发了大量 Java 代码,因此 Clojure 与 Java 工具的良好集成对我很有帮助(例如,我使用 Maven、Eclipse 和逆时针插件进行 Clojure 开发)

  • 向量 [1 2 3]、映射 {:bob 10, :jane 15} 和集合 #{"a" "b" "c"} 的语法很好 - 我认为这些对于现代编程来说非常重要的工具(当然还有列表!)

  • 我个人喜欢使用方括号来绑定表单:例如(defn foo [a b] (+ a b)) - 我认为它使代码更清晰易读。

  • 强调具有持久、不可变数据结构的惰性函数式编程 - 特别是所有核心 Clojure 库都默认支持这一点

  • 多核并发的出色 STM 实现。我相信 Clojure 拥有目前所有语言中最好的并发故事(参见 video for more elaboration by Rich Hickey himself

  • 这是我个人更喜欢的 Lisp-1(类似于 Scheme)(我认为在函数式语言中,将函数和数据保存在同一个命名空间中是有意义的)

【讨论】:

  • STM +1。它本身就足以证明使用 Clojure 是合理的。
  • 您仍然可以使用库 CL-STM 获取 STM。
  • @AndréCaron 仅在您需要时使用。
  • 如果您想编写一个简单的 web 应用程序,并将其托管在一个便宜的每月 5 美元的主机上,这显然是由于 JVM 而无法使用 Clojure 实现的,对吗?
  • @Hexatonic 我不是很有经验,但很难相信现在使用的机器没有 JVM。
【解决方案2】:

这是一个带有comparison of Scheme (Racket mostly) and Clojure 的好视频。

公平地说,Racket 也为数据类型(#hash、#、方括号等)提供语法糖(额外的阅读器内容)

另外,Clojure 进行正确尾调用的唯一方法是使用 recur,这是编译到 JVM 的缺点。

请注意,recur 是 Clojure 中唯一不消耗堆栈的循环结构。没有尾声 不鼓励优化和使用自调用来循环未知边界。 recur 是 功能及其在尾部位置的使用由编译器验证。 (Special Forms)。

【讨论】:

  • 看起来该链接上的视频可以在这里找到:vimeo.com/22675078
  • 还有trampoline用于尾调用。
【解决方案3】:

请记住,Clojure 是一种语言和一种实现(通常在 JVM 上)。 Common Lisp 是一种具有十多种不同实现的语言。所以我们这里有一个类别不匹配。例如,您可以将 Clojure 与 SBCL 进行比较。

一般:

  • 在 JVM 上运行的 Common Lisp 版本:ABCL

  • 大多数其他 Common Lisp 实现都没有

  • 大多数 CL 实现都具有多任务处理能力,一个库提供一个通用接口

  • Common Lisp 具有数组语法。其他数据类型的语法可由用户编写并由各种库提供。

  • Common Lisp 既不支持尾调用优化也不支持延续。实现提供 TCO,库提供某种形式的延续。

【讨论】:

    【解决方案4】:

    Clojure 和 Common Lisp 之间的一个重要区别是 Clojure 对函数式编程更加规范。 Clojure 的哲学、习语和某种程度的语言/库强烈鼓励并且有时坚持您以函数式方式编程(没有副作用,没有可变状态)。

    Common Lisp 绝对支持函数式编程,但它也允许可变状态和命令式编程。

    当然,函数式编程在并发和其他方面有很多好处。但在所有其他条件相同的情况下,可以选择要针对每种情况使用哪种方法也很好。 Clojure 并没有完全禁止命令式编程,但它比 Common Lisp 更不适应这种风格。

    【讨论】:

    • @Charlie Flowers:我相信在 Common Lisp 中可以以“纯函数式”风格(持久数据结构支持等)进行编程,但需要纪律。对吗?
    • 只是对“无副作用,无可变状态”的澄清 - Clojure 确实具有可变状态(引用、原子、代理等都是可变的)但要求您以受控方式访问它(即通过STM机制和相关的事务更新语义)
    • @mikera:除了 Clojure 依赖于使用 Java 库才能使用之外,所有这些库都需要命令式风格并且充满副作用。我发现与 Java 的绑定是一种有毒的礼物......
    • @Andre - 当然,如果您决定使用需要可变状态和命令式语义的库,那么您必须对此进行管理。这与您从任何其他语言访问此类库没有什么不同。但是你有两个不错的选择:a) 不要使用这样的库——你可以在纯 Clojure 中编写非常好的代码,或者 b) 将与这些库交互的复杂性包装在一个不错的 Clojure 风格的函数式接口中,这通常很容易使用宏或代理等。总的来说,我发现利用 Java 库的能力比问题大得多。
    • @mikera:图书馆确实有好处。我只是指出,使用 Java 库(这是 Rich Hickey 对该语言的主要目标之一)确实违背了 Clojure 的“比其他 lisp 功能更强大”的方面。我的评论的意思是:“除非您重写/包装这些库,否则您将获得看起来像命令式的代码,并且不会从 Clojure 更好的部分中受益”。
    猜你喜欢
    • 1970-01-01
    • 2011-02-25
    • 2011-03-21
    • 2012-03-25
    • 2020-07-02
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多