如果函数式语言真的很简洁,为什么它们在语言大战中没有取得更好的排名呢?

发布于 2024-09-16 08:06:07 字数 1036 浏览 4 评论 0原文

我比较了语言枪战游戏中的语言 仅按代码大小。这是我得到的总结(最短的第一个,按相似的分数分组)。

  1. Python、Ruby、JavaScript、Perl、Lua、PHP、Mozart/OZ
  2. OCaml、Erlang、Racket、Go、Scala、F#、Smalltalk
  3. Pascal、Clean、Haskell、Common Lisp、C#、Java、C
  4. C++、Ada、ATS

我想知道为什么。获胜者似乎是普通的旧动态语言。 Erlang、Racket(née PLT Scheme)和 F# 都表现良好。 Haskell 和 Common Lisp 看起来并不比声称冗长的 Java 更简洁。

更新:

我发现了一篇富有洞察力的帖子 关于这个主题的图表。我还发现了大型程序的类似语言比较(一个简单的光线追踪器)。总而言之,我不会说我得到了“正确”的答案,但我得到了一些值得思考的东西。

I compared the languages at the language shootout game by their code size only. Here is a summary of what I got (shortest first, grouped by similar score).

  1. Python, Ruby, JavaScript, Perl, Lua, PHP, Mozart/OZ
  2. OCaml, Erlang, Racket, Go, Scala, F#, Smalltalk
  3. Pascal, Clean, Haskell, Common Lisp, C#, Java, C
  4. C++, Ada, ATS

I wonder why. The winners seem to be plain old dynamic languages. Erlang, Racket (née PLT Scheme), and F# are doing OK. Haskell and Common Lisp don't look more concise than claimed-to-be-verbose Java.

UPDATE:

I've found an insightful post on this topic with charts. I also found a similar comparison of languages for a larger program (a simple ray tracer). Altogether, I wouldn't say I got "the" answer, but I got some food for thought.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

烧了回忆取暖 2024-09-23 08:06:07

如果函数式语言真的是
简洁...

1 - 大型编程与小型编程不同

这些微小的基准游戏程序不应被视为每种语言提供的抽象和模块化如何应用于大型编程的示例。

2 - 您在基准测试游戏摘要页面中看到的大部分内容仅指为每种语言实现贡献的最快程序(较慢的程序通常会在一段时间后从网站上删除 - 何时以及哪些较慢的程序被删除删除大多是任意的)。

{编辑:Adam,因为您不想相信我的话,即摘要页面仅指最快的程序 - 查看过滤数据行的脚本以查找“哪种编程语言是最好的?”页。查看 lib_scorecard.php - Alioth 颁发自己的安全证书,因此您的浏览器会抱怨。}

因此,以 Haskell 为例,您正在查看的代码大小已贡献的最快的 Haskell 程序。

3 - 流星竞赛程序均未被删除,流星竞赛是一场没有限制的编程竞赛 - 最小的流星竞赛 Haskell 程序是最慢的流星竞赛 Haskell 程序

If functional languages are really
concise...

1 - Programming in the large is different than programming in the small.

Nothing about those tiny benchmarks game programs should be taken as an example of how the abstractions and modularisation provided by each language would apply to programming in the large.

2 - Most of what you see in the benchmarks game summary pages only refers to the fastest programs contributed for each language implementation (slower programs are usually removed from the website after a while - when and which slower programs are removed is mostly arbitrary).

{edit: Adam, as you don't wish to take my word for it that the summary pages only refer to the fastest programs - look at the script that filters data rows for the "Which programming language is best?" page. Look at line 80 and line 82 in function ValidRowsAndMins in lib_scorecard.php - Alioth issue their own security certificate so your browser will complain.}

So to take Haskell as an example, you're looking at code size of the fastest Haskell programs that have been contributed.

3 - None of the meteor-contest programs have been removed, and meteor-contest is a programming contest without restriction - the smallest meteor-contest Haskell program is the slowest meteor-contest Haskell program.

雨落星ぅ辰 2024-09-23 08:06:07
  1. 没有一种语言总是优于另一种语言(嗯,有一些例外......;)),因此这同样适用于一组广泛分类的语言。基准测试涵盖了广泛的主题,X 可能比 Y 更不适合其中一个
  2. 。源代码是压缩的,我们真的不知道程序有多少行,长度是多少(是的,这是一个指标
  3. )许多函数式语言仍然比广泛使用的命令式静态语言做得更好 - 这并不是说函数式编程语言不简洁,而是动态语言允许更简洁的程序
  4. 至少在 Haskell 中,简洁性的很大潜力来自于你可以的抽象自己构建 - 但您必须自己构建它们并将它们包含在您的解决方案中。聪明的 Haskell 黑客可能会用 20 行实现一个 monad,这样就可以用 20 行而不是 30 行来解决一个小问题 - 这种抽象对于一个小程序来说并没有什么回报,但可以在更大的程序中节省许多行(例如,200 行)共 300 个)计划。我想这同样适用于 Lisps(只有宏而不是 monad),
  5. 不要太认真地对待粉丝们。 FP 很棒,值得研究,但它不能治愈癌症,也不能神奇地将任何代码缩短 25%
  6. 他们仍然可以在某些领域击败动态语言:例如,树状数据结构及其处理表达极其得益于代数数据类型和模式匹配,在许多函数式语言中自然如此。
  1. No language is always superior to another (well, there are a few exceptions... ;) ), so same applies for a group of broadly categorized languages. The benchmarks cover a broad array of topics, and X may be less suited for one than Y.
  2. The source code is gzipped, we don't really know how many lines of what length the programs were (yeah, it's an indicator)
  3. A considerable number of functional languages still do much better than the widespread imperative, static languages - it's not that functional programming languages aren't succinct, but the dynamic languages allow even more succinct programs
  4. At least in Haskell, much potential for conciseness comes from abstractions you can build yourself - but you do have to build them yourself and include them in your solution. A clever Haskell hacker may implement a monad in 20 lines that allows solving a small problem in 20 lines instead of 30 - the abstraction doesn't pay off for a small program, but could save many lines in a larger (eg. 200 lines instead of 300) program. I guess the same applies for Lisps (only macro instead of monad)
  5. Don't take the fanboys too seriously. FP is awesome and worth looking into, but it doesn't cure cancer and doesn't magically shorten any code by 25%
  6. They can still beat dynamic languages for some areas: For example, tree-like data structures and their processing is expressed extremely naturally in many functional languages, thanks to algebraic data types and pattern matching.
冷了相思 2024-09-23 08:06:07

这似乎是一个发泄的机会:

是否有统计研究表明Python“更有生产力”?

重点是,最初的问题是试图使用一些(微不足道的、不恰当的)数据来对编程语言之间的比较进行概括。但事实上,几乎不可能使用任何数据对编程语言进行任何合理的一般定量比较。

不过,这里有一些值得深思的地方:

  • 在所有条件相同的情况下,动态类型语言可能会更简洁,因为它们不需要花时间描述数据类型
  • 在所有条件相同的情况下,在静态类型语言中,类型 -对我来说,推断语言可能更简洁,因为它们不需要到处声明类型在
  • 所有条件相同的情况下,在静态类型语言中,那些具有泛型/模板的语言可能更简洁,因为没有它们的语言需要重复代码或强制转换和间接
  • ,具有简洁 lambda 语法的语言可能会更加简洁,因为 lambda 可能是编程中避免重复和样板代码的最重要的抽象

在所有条件相同的情况下 远射。

This seems like an opportunity to whip out:

Are there statistical studies that indicates that Python is "more productive"?

The point being, the original question is trying to use some (paltry, inappropriate) data to make a generalization about comparisons among programming languages. But in fact, it's nigh impossible to use any data to make any kind of reasonable general quantitative comparisons about programming languages.

Here is some food for thought, though:

  • All things being equal, dynamically-typed languages are likely to be more concise, since they don't need to spend time describing data types
  • All things being equal, among statically-typed languages, type-inferred languages are likely to me more concise, since they don't need to declare types all over the place
  • All things being equal, among statically-typed languages, those with generics/templates are more likely to be concise, since languages without them require repeated code or casts and indirection
  • All things being equal, languages with a concise lambda syntax are likely to be more concise, since lambda is perhaps the most important abstraction in programming for avoiding repetition and boilerplate

That said, all things are not equal, not by a long shot.

够钟 2024-09-23 08:06:07

Alioth 游戏中的程序并不能真正代表一般语言中的程序。其一,其中的实现针对 Shootout 的特定基础设施进行了高度优化,这可能会导致函数式语言中的代码不太惯用且更加臃肿。这类似于一些 Ruby 库用 C 语言编写性能关键型代码的方式 — 查看该 C 代码并声明 Ruby 臃肿且低级,这实际上不会给该语言带来公平的震动。

另一方面,函数式语言被吹捧为如此简洁的一个重要原因是它们擅长进行抽象。这在大型程序中往往比在单函数奇迹中更有帮助,因此专门为简单简洁而设计的语言在那里赢得了巨大的胜利。 Python、Perl 和 Ruby 是专门为缩短程序而设计的,而大多数函数式语言都有其他目标(尽管这并不是说它们只是忽略代码大小)。

The programs in the Alioth game are not really representative of programs in those languages in general. For one, the implementations there are highly optimized toward the Shootout's specific infrastructure, which can lead to less idiomatic and more bloated code in a functional language. It's similar to how some Ruby libraries will write performance-critical code in C — to look at that C code and declare Ruby to be bloated and low-level would really not be giving the language a fair shake.

For another, a big part of why functional languages are touted as being so terse is that they're good at making abstractions. This tends to help more in big programs than in one-function wonders, so languages specifically engineered for easy brevity win big there. Python, Perl and Ruby are specifically designed to make short programs short, whereas most functional languages have other goals (though that's not to say they just ignore code size either).

厌倦 2024-09-23 08:06:07

我最近将一个相对较短的 Java 程序移植到 OCaml 中。我过去涉足过 SML 和 Haskell,并且在 C 方面拥有丰富的经验。

在这个答案中,我对命令式代码与纯函数式代码(即没有突变)进行了比较。如果您允许命令式代码潜入其他功能程序中,您在比较什么?

根据我的经验,纯函数式编程(PFP)很优雅,但并不比命令式更简洁。 PFP 中的“声明”样板较少,但“转换”样板较多;例如,从元组中解包、尾递归辅助函数等。因此,这两种范式都不允许不受阻碍地表达程序的纯粹“内容”。

PFP 运行某些东西的成本较低,并且编写一个程序来证明给定算法原则上可以工作在 PFP 中效果很好。但是,增强它以使其成为“现实世界”,让它处理错误条件和非法输入和打印诊断会增加很多膨胀,而这些膨胀在命令式语言中更容易克服。

I have recently ported a relatively short Java program to OCaml. I've dabbled in SML and Haskell in the past, plus extensive experience with C.

In this answer, I address a comparison of imperative to purely functional code (i.e.; no mutations). If you allow imperative code to sneak into otherwise functional programs, what are you comparing?

In my experience, purely functional programming (PFP) is elegant, but not more concise than imperative. There is less "declarations" boilerplate in PFP but more "conversion" boilerplate; e.g., unpacking from tuples, tail recursive helper functions, etc. So, neither paradigm allows the unencumbered expression of the pure "meat" of a program.

PFP has lower costs to get something running, and writing a program to demonstrate that a given algorithm works in principle goes over well in PFP. But, augmenting it to make it "real-world", having it deal with error conditions and illegal input and print diagnostics adds a lot of bloat that would have gone over more easily in an imperative language.

对你而言 2024-09-23 08:06:07

必须与可用于您的第 1 级中的大多数语言的扩展 OOP 库有关,并且只是简单的旧技巧,例如 shell 调用的反引号和 perl 正则表达式语法。 如果不是面向对象语言中充斥着抽象概念,那么放弃 python

pw = file("/etc/passwd")
for l in pw:
    print l.split(':')[0]

打印系统上的所有用户名将需要更多代码。我并不是说这在其他范式中不能完成,但趋势是每种类型都有很多成员函数,使繁琐的任务变得简单。就我个人而言,我发现纯函数式语言仅对学术目的有用(但话又说回来,我知道什么)。

Must have something to do with expansive OOP libraries available to most of the languages in your level 1 and just plain old hacks like backticks for shell calls and perl regex syntax. Going off of python

pw = file("/etc/passwd")
for l in pw:
    print l.split(':')[0]

Printing all the usernames on a system, would take a lot more code if it weren't for the abstractions that OO languages are littered with. I'm not saying that it can't be done in other paradigms, but the trend is that every type has a lot of member functions that make tedious tasks simple. Personally I find purely functional languages to be only useful for academic purposes (but then again what do I know).

关于从前 2024-09-23 08:06:07

您应该考虑这样一个事实:您的第 1 组语言(脚本)比 C/C++ 慢 30 到 100 倍,对于函数式语言来说则慢 2 到 7 倍。列表中的程序针对速度进行了优化,测量其他任何内容是次要问题,这并不是语言真实状态的良好指标。
查看 ,其中代码大小和运行时间的权重均为 1。通过这种方式,您可以比较速度/可维护性比率,这似乎是比代码大小更好的指标。

You should consider the fact that your group 1 languages (scripting) are 30 to 100 times slower than C/C++, for the functional languages the same is between 2 and 7 times. The programs in the list are optimized for speed and measuring anything else is a secondary issue which isn't really a good indicatior of the real state of the language.
It is more interesting to look at the table where code size and running time each have weight 1. This way you get a comparison of the speed/maintainability ratio which seems a better metric than just code size.

倒带 2024-09-23 08:06:07

获胜者似乎是普通的老式动态语言。

Lisp 是一个明显的反例,它是一种极其冗长的简单古老的动态语言。另一方面,APL/J/K 可能比任何其他语言都简洁得多,而且它们是动态的。还有数学...

Haskell 和 Common Lisp 看起来并不比声称冗长的 Java 更简洁。

您的数据适用于已针对性能进行优化的小型程序,并且测量的是在特定设置上使用 GZIP 算法压缩后的代码大小,因此您不可能仅从它们得出一般性结论。也许更有效的结论是,您正在观察性能优化导致的膨胀,因此数据中最简洁的语言是那些无法优化的语言,因为它们从根本上来说效率低下(Python、Ruby、Javascript、Perl、Lua、PHP)。相反,Haskell 可以通过足够的努力进行优化,以创建快速但冗长的程序。这真的是 Haskell 与 Python 相比的劣势吗?另一个同样有效的结论是,Python、Ruby、Perl、Lua 和 PHP 在该设置上使用 GZIP 算法可以更好地压缩。也许如果您使用游程编码或算术编码或 LZ77/8 重复实验,也许使用 BWT 预处理或其他算法,您会得到完全不同的结果?

该网站的代码中还存在大量毫无价值的代码。查看这段 OCaml 代码片段,仅当您的 OCaml 安装已过时两代时才需要:

(* This module is a workaround for a bug in the Str library from the Ocaml
 * distribution used in the Computer Language Benchmarks Game. It can be removed
 * altogether when using OCaml 3.11 *)
module Str =
struct
  include Str

  let substitute_first expr repl_fun text =
    try
      let pos = Str.search_forward expr text 0 in
      String.concat "" [Str.string_before text pos;
                        repl_fun text;
                        Str.string_after text (Str.match_end())]
    with Not_found ->
      text

  let opt_search_forward re s pos =
    try Some(Str.search_forward re s pos) with Not_found -> None

  let global_substitute expr repl_fun text =
    let rec replace accu start last_was_empty =
      let startpos = if last_was_empty then start + 1 else start in
      if startpos > String.length text then
        Str.string_after text start :: accu
      else
        match opt_search_forward expr text startpos with
        | None ->
            Str.string_after text start :: accu
        | Some pos ->
            let end_pos = Str.match_end() in
            let repl_text = repl_fun text in
            replace (repl_text :: String.sub text start (pos-start) :: accu)
                    end_pos (end_pos = pos)
    in
      String.concat "" (List.rev (replace [] 0 false))

  let global_replace expr repl text =
    global_substitute expr (Str.replace_matched repl) text
  and replace_first expr repl text =
    substitute_first expr (Str.replace_matched repl) text
end

单核版本通常包含大量并行代码,例如 OCaml 中的正则表达式-dna。看看 fasta 中的怪物OCaml:整个程序被复制两次,并且它会切换字大小!我的磁盘上有一个旧的 OCaml 版本的 fasta,其大小还不到该版本的五分之一...

最后,我应该指出,我已向该站点贡献了代码,但由于它太好了而被拒绝。撇开政治不谈,OCaml 二叉树曾经包含“由 Isaac Gouy 去优化”的语句(尽管注释已被删除,但去优化仍然存在,使得 OCaml 代码更长、更慢),因此您可以假设所有结果经过主观修改,专门引入了偏差。

基本上,利用如此低质量的数据,你无法得出任何有洞察力的结论。您最好尝试找到已在语言之间移植的更重要的程序,但即使如此,您的结果也将是特定于领域的。我建议完全忘记点球大战......

The winners seem to be plain old dynamic languages.

Lisp is an obvious counter example, being a plain old dynamic language that is extremely verbose. On the other hand, APL/J/K would probably be much more concise than any of the other languages and they are dynamic. Also Mathematica...

Haskell and Common Lisp don't look more concise than claimed-to-be-verbose Java.

Your data are for tiny programs that have been optimized for performance and the measure is code size after compression using the GZIP algorithm on a particular setting so you cannot possibly draw general conclusions from them alone. Perhaps a more valid conclusion would be you are observing the bloat that results from performance optimizations so the most concise languages from your data are those that cannot be optimized because they are fundamentally inefficient (Python, Ruby, Javascript, Perl, Lua, PHP). Conversely, Haskell can be optimized with enough effort to create fast but verbose programs. Is that really a disadvantage of Haskell vs Python? Another equally valid conclusion is that Python, Ruby, Perl, Lua and PHP compress better using the GZIP algorithm on that setting. Perhaps if you repeat the experiment using run-length encoding or arithmetic coding or LZ77/8, maybe with BWT preconditioning, or another algorithm you would get completely different results?

There is also a huge amount of worthless cruft in the code on that site. Look at this snippet of OCaml code that is only necessary if your OCaml install is two generations out of date:

(* This module is a workaround for a bug in the Str library from the Ocaml
 * distribution used in the Computer Language Benchmarks Game. It can be removed
 * altogether when using OCaml 3.11 *)
module Str =
struct
  include Str

  let substitute_first expr repl_fun text =
    try
      let pos = Str.search_forward expr text 0 in
      String.concat "" [Str.string_before text pos;
                        repl_fun text;
                        Str.string_after text (Str.match_end())]
    with Not_found ->
      text

  let opt_search_forward re s pos =
    try Some(Str.search_forward re s pos) with Not_found -> None

  let global_substitute expr repl_fun text =
    let rec replace accu start last_was_empty =
      let startpos = if last_was_empty then start + 1 else start in
      if startpos > String.length text then
        Str.string_after text start :: accu
      else
        match opt_search_forward expr text startpos with
        | None ->
            Str.string_after text start :: accu
        | Some pos ->
            let end_pos = Str.match_end() in
            let repl_text = repl_fun text in
            replace (repl_text :: String.sub text start (pos-start) :: accu)
                    end_pos (end_pos = pos)
    in
      String.concat "" (List.rev (replace [] 0 false))

  let global_replace expr repl text =
    global_substitute expr (Str.replace_matched repl) text
  and replace_first expr repl text =
    substitute_first expr (Str.replace_matched repl) text
end

The single core versions often contain lots of code for parallelism, e.g. regex-dna in OCaml. Look at the monstrosity that is fasta in OCaml: the entire program is duplicated twice and it switches on the word size! I have an old OCaml version of fasta on disk here that is less that a fifth the size of that one...

Finally, I should note that I have contributed code to this site only to have it rejected because it was too good. Politics aside, the OCaml binary-trees used to contain the statement "de-optimized by Isaac Gouy" (although the comment has been removed, the deoptimization is still there making the OCaml code longer and slower) so you can assume that all of the results have been subjectively doctored specifically to introduce bias.

Basically, with such poor quality data you cannot hope to draw any insightful conclusions. You'd be much better off trying to find more significant programs that have been ported between languages but, even then, your results will be domain specific. I recommend forgetting about the shootout entirely...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文