If functional languages are really concise, why don't they have a better rank in the language shootout game?
我只按代码大小比较了语言射击游戏中的语言。这里是我得到的总结(最短的第一个,按相似的分数分组)。
我不知道为什么。胜利者似乎是简单的老式动态语言。Erlang、Racket(N_E PLT方案)和F_的表现都不错。Haskell和CultLisp并不比声称是冗长的Java更简洁。
更新:
我用图表找到了一篇关于这个主题的有见地的文章。我还发现了一个更大程序(一个简单的光线跟踪器)语言的类似比较。总的来说,我不会说我得到了"答案",但我得到了一些思考的食物。
If functional languages are really
concise...
1-大的编程与小的编程不同。
这些小基准游戏程序不应该被看作是每种语言所提供的抽象和模块化将如何应用于大规模编程的一个例子。
2-在基准游戏摘要页面中看到的大多数内容仅指为每种语言实现贡献的最快的程序(较慢的程序通常在一段时间后从网站上删除-删除较慢的程序的时间和内容大多是任意的)。
编辑:Adam,因为您不想相信我的话,摘要页只引用最快的程序-请看为"哪种编程语言最好"筛选数据行的脚本。页。查看lib_scorecard.php-alioth函数validrowsandmins中的第80行和第82行,然后颁发自己的安全证书,这样您的浏览器就会抱怨。
所以以haskell为例,您将看到贡献最快的haskell程序的代码大小。
3-没有一个流星比赛项目被删除,流星比赛是一个没有限制的节目比赛-最小的流星比赛哈斯克尔计划是最慢的流星比赛哈斯克尔计划。
这似乎是一个快速发展的机会:
是否有统计研究表明python"更有效率"?
关键是,最初的问题是试图使用一些(微不足道的,不适当的)数据来概括编程语言之间的比较。但事实上,几乎不可能用任何数据对编程语言进行任何合理的一般定量比较。
不过,这里有一些思考的食物:
- 所有东西都一样,动态类型语言可能更简洁,因为它们不需要花时间描述数据类型。
- 在静态类型语言中,所有东西都一样,类型推断语言对我来说可能更简洁,因为它们不需要到处声明类型。
- 在静态类型语言中,所有事物都是相等的,那些具有泛型/模板的语言更可能是简洁的,因为没有它们的语言需要重复的代码或强制转换和间接寻址。
- 所有东西都一样,具有简洁lambda语法的语言可能更简洁,因为lambda可能是编程中最重要的抽象,以避免重复和样板文件。
也就是说,一切都不平等,不可能一帆风顺。
我最近移植了一个比较短的Java程序到OCAML。我过去曾涉足过SML和Haskell,以及在C方面的丰富经验。
在这个答案中,我将讨论命令式代码与纯功能性代码的比较(即,没有突变)。如果您允许命令式代码潜入其他功能性程序,那么您比较什么?
在我的经验中,纯函数编程(pfp)是优雅的,但并不比命令式更简洁。pfp中的"声明"样板文件更少,但"转换"样板文件更多;例如,从元组解包、尾部递归助手函数等。因此,两种范例都不允许对程序的纯"meat"进行无阻碍的表达式。
pfp具有较低的运行成本,并且编写一个程序来证明给定的算法在原则上在pfp中运行良好。但是,对其进行扩充,使其成为"现实世界",处理错误条件和非法的输入和打印诊断,会增加许多膨胀,这在命令式语言中更容易克服。
Alioth游戏中的程序并不能真正代表这些语言的程序。首先,这里的实现针对shootout的特定基础结构进行了高度优化,这可能会导致函数语言中的代码不太惯用,也更臃肿。这类似于一些Ruby库将如何用C语言编写性能关键的代码——查看C代码并声明Ruby是膨胀的,低级别的代码并不会给语言带来公平的震动。
另一方面,功能语言之所以被吹捧为如此简洁,很大程度上是因为它们擅长抽象。这在大型程序中比在一个函数奇迹中有更多的帮助,因此专门为简单简洁设计的语言在那里赢得了巨大的成功。python、perl和ruby是专门为使短程序变短而设计的,而大多数函数语言都有其他目标(尽管这并不是说它们也只是忽略代码大小)。
因为有些算法在功能性表达时更简洁,而其他算法在迭代性表达时更简洁。一般来说,这取决于您对数据与当前数据状态之间关系的关注程度。
还请记住,您可以用Python之类的语言进行函数式编程,程序员将在这些语言中使用fp,用于程序的某些部分,这样做更简洁或更高效,而且通常不知道他们在执行fp。而对于纯函数语言,在更简洁或更高效的情况下,您没有选择进行迭代编程。
你应该考虑的事实是,你的组1种语言(脚本)比C/C++速度慢30到100倍,因为函数语言在2到7倍之间。列表中的程序针对速度进行了优化,测量任何其他内容都是次要问题,这并不能很好地反映语言的实际状态。更有趣的是,看看表中代码大小和运行时间各占1的权重。通过这种方式,您可以比较速度/可维护性比率,这似乎比代码大小更好。
必须与1级语言中的大多数语言都可以使用的扩展OOP库有关,而且只是简单的老黑客程序,比如shell调用的backticks和perl regex语法。离开Python
1 2 3 | pw = file("/etc/passwd") for l in pw: print l.split(':')[0] |
在一个系统上打印所有的用户名,如果不是因为OO语言所包含的抽象,就需要更多的代码。我并不是说它不能在其他范例中实现,但趋势是每种类型都有许多成员函数,它们使得冗长的任务变得简单。就我个人而言,我发现纯粹的功能性语言只对学术目的有用(但我又知道什么)。
The winners seem to be plain old dynamic languages.
Lisp是一个明显的反例,它是一种非常冗长的简单的老动态语言。另一方面,APL/J/K可能比任何其他语言都要简洁得多,而且它们是动态的。还有数学…
Haskell and Common Lisp don't look more concise than claimed-to-be-verbose Java.
您的数据是针对已针对性能进行了优化的小型程序的,并且在对特定设置使用gzip算法进行压缩后,度量值是代码大小,因此您不可能单独从中得出一般结论。也许一个更有效的结论是,您正在观察性能优化导致的膨胀,因此数据中最简洁的语言是那些无法优化的语言,因为它们根本上效率低下(python、ruby、javascript、perl、lua、php)。相反,haskell可以通过足够的努力进行优化,以创建快速但冗长的程序。这真的是haskell和python的劣势吗?另一个同样有效的结论是,在该设置上使用gzip算法可以更好地压缩python、ruby、perl、lua和php。也许,如果您使用运行长度编码或算术编码或LZ77/8重复实验,或者使用BWT预处理,或者其他算法,您会得到完全不同的结果?
该站点上的代码中也有大量毫无价值的代码。看看这段OCAML代码片段,只有当您的OCAML安装已过时两代时才需要它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | (* 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中的regex dna。看看在ocaml中fasta的可怕之处:整个程序被复制了两次,它打开了单词大小!我在磁盘上有一个旧的OCAML版本的fasta,比那个小五分之一…
最后,我要注意的是,我为这个站点贡献了代码,结果却因为太好而被拒绝了。撇开政治因素不谈,ocaml二叉树用于包含"de optimized by isaac gouy"(尽管注释已被删除,但去优化仍然存在,使得ocaml代码越来越长,越来越慢),因此可以假设所有结果都经过了主观处理,专门引入了偏见。
基本上,由于数据质量太差,你不可能希望得出任何有见地的结论。如果你想找到在不同语言之间移植的更重要的程序,你会好得多,但是即使这样,你的结果也会是特定于领域的。我建议完全忘记枪战…