我是OCaml的新手。我最近偶然发现此页面,列出了对OCaml的大量批评。
看到页面很旧(2007年):今天列出的哪些项目符号仍然正确?例如:仍然不可能打印通用对象吗?
我想明确指出,我不是要讨论其中表达的意见。我在问列出的信息(例如整数无警告溢出)是否仍然适用于OCaml的最新版本
我是OCaml的新手。我最近偶然发现此页面,列出了对OCaml的大量批评。
看到页面很旧(2007年):今天列出的哪些项目符号仍然正确?例如:仍然不可能打印通用对象吗?
我想明确指出,我不是要讨论其中表达的意见。我在问列出的信息(例如整数无警告溢出)是否仍然适用于OCaml的最新版本
Answers:
本文在几个地方讨论:
总结一下:是的,OCaml不是Lisp,不是,它不是完美的(这意味着什么?)。我认为博客文章中提到的观点与O'Caml的日常程序员无关。
学习过O'Caml之后,我认为这是一种有趣的语言,可以帮助您构建甚至都不敢用C / C ++ / Java编写的程序:例如,看看 Frama-C。
关于O'Caml的最新描述,我建议您阅读其功能:该语言促进了强大的静态类型检查技术,该技术使实现专注于产生高性能但安全的运行时。
重要提示:我不是OCaml专家:如果您是其中的一员,并且看到我写的东西严重错误,请纠正我。我将相应地编辑此帖子。
错误的安全感
这是事实,但显而易见。
静态类型为您提供了您可以信任的程序属性子集的证明。除非您接受所有正式的程序,否则普通(非玩具)程序将受到编程错误错误的影响,这些错误错误只能在运行时才能看到。
到那时,可以应用动态检查技术:OCaml编译器具有用于生成带有调试信息的可执行文件的标志,依此类推……或者,它可以生成盲目的信任程序员并尽可能擦除类型信息的代码。希望使用健壮程序的程序员应明确实现动态检查。
同样的情况适用于例如Common Lisp,但相反:首先是动态类型,其次是可选的类型声明和编译器指令。
几种基本类型
仍然适用:核心语言没有改变(或没有太大变化)。
无声整数溢出
在大多数语言中,这是整数溢出是由人工检查的规范。我不知道有哪个库会进行类型检查操作以验证是否会发生溢出。
模块不变性
作者提到了函子,但我看不到他的示例无法实现。阅读https://realworldocaml.org的“ 头等舱模块”一章,似乎可以将这些模块用于组成和构建新模块。当然,修改现有模块需要修改源代码,但同样,这在编程语言中并不罕见。
“从语义上讲,函数是在线编译的”
上面的reddit线程不同意,说绑定是在链接时解决的。但是,这是一个实现细节,我认为强调的语义与功能解析的方式有关。例:
let f x y = x + y ;;
let g a b = f b a ;;
let f x y = x * y ;;
exit (g 2 3) ;;
上面的程序编译,并且当被执行时,返回图5,因为g
是用所述第一版本中定义f
,只是原样如果主叫函数g
内联调用f
。顺便说一句,这并不是“坏”的,这与奥卡姆的名字遮蔽规则是一致的。
总结一下:是的,模块是不可变的。但是它们也是可组合的。
多态性导致运行时类型错误
我无法重现上述错误。我怀疑这是编译器错误。
实际上,除了预处理器(OcamlP4,OcamlP5等)之外,没有宏。
包装器(打开文件)
知道UNWIND-PROTECT会很有用,看到更多语言中缺少它确实很痛苦。以下是一些选项:
地方
我认为OCaml中不存在通用引用。
记录字段命名地狱
是的,但是您应该使用模块:
句法
仍然适用(但实际上,这只是语法)。
没有多态
仍然适用,但不知何故有些人更喜欢 Lisp的数字塔(我不知道为什么)。我想它有助于类型推断。
功能集不一致
请参阅“ 包含OCaml电池”项目。特别是 BatArray,例如map2
for数组。
没有动态变量
可以实现:
可选〜参数很烂
受语言限制,您不能在Common Lisp中混合使用可选参数和关键字参数。这是不是很烂?(当然,这可以通过宏进行更改(例如参见我的回答))。有关O'Caml中的可选参数和命名参数,请参见O'Caml的文档。
部分参数应用程序不一致
我不认为这在实践中真的很烦人。
算术的可读性
它成立了,但是您可以根据需要使用R或Python解决数值问题。
沉默的名字冲突解决
仍然适用,但是请注意,这已经有据可查。
没有对象输入/输出
仍然适用。
这些每天都在变化:没有确切的答案。
最后,
“即使您认为OCaml很烂,并且您不打算使用它,也应该尝试OCaml(或者更好的是,Haskell)。没有它,您的计算机科学教育就不完整,就像没有Lisp和C(或,更好的是,大会)曝光。”
...仍然适用。
看到页面很旧(2007年):今天列出的哪些项目符号仍然正确?
错误的安全感。这是无稽之谈。
基本类型很少。OCaml现在具有字节和字节数组,但是没有内置的unicode字符串,16位整数,无符号整数,32位浮点数,向量或矩阵。第三方库提供了其中的一些。
静音整数溢出。不变,但这从来不是问题。
模块的不变性。他建议功能和模块应该可变,这对Lisp来说是一个冷酷的回想,这是一个非常糟糕的主意。当然,您可以使用取代模块include
,但不能对其进行突变。
多态性会导致运行时类型错误。这是OCaml的大问题,尚未解决。当您的类型演变成多态相等性时,当它们遇到诸如函数之类的类型且调试问题非常困难时,比较和哈希运算将开始失败。F#对这个问题有很好的解决方案。
没有宏。具有讽刺意味的是,当他写这篇OCaml时,它实际上完全支持宏,但是他们现在决定退出该功能。
包装纸。这是一个实际的问题,尚未解决。try ... finally
在OCaml语言中仍然没有构造,并且在stdlib中也没有实现它的包装器。
地方。不变但没有问题。
记录字段命名地狱。使用模块正确组织代码。
语法。不变但没有问题。
没有多态性。当他写这封信时,这简直是胡说八道,没有任何改变。
函数集不一致。OCaml仍然没有cons
功能。没关系。我不想用我的语言来介绍Lisp,谢谢。
没有动态变量。对OCaml来说是一件好事。关于OCaml仍然是一件好事。
可选〜参数很烂。可选参数不可靠。我给Microsoft徽章,让他们为F#添加可选参数。
部分参数应用不一致。h?
算术的可读性。自从大约8年前我停止使用OCaml以来,这种情况已经改变。显然现在您可以做到Int64.((q * n - s * s) / (n - 1L))
。
沉默的名字冲突解决。他试图像在Lisp中一样在REPL中进行全面的软件开发。不要在OCaml中这样做。只能使用REPL来使用文件和批处理编译,仅用于测试,运行一次性代码和交互式技术计算。
评估顺序。他写这是错的。评估顺序在OCaml中未定义。
没有对象输入/输出。他引用了一个第三方库,该库已经解决了这个“问题”。
编译器在出现第一个错误后停止。h?
没有对本机编译的可执行文件的堆栈跟踪。固定。
调试器糟透了。我从未使用过调试器。静态类型检查几乎捕获了我所有的错误。
GC很烂。我发现OCaml的GC很好,除了一个主要问题:全局锁阻止了并行编程。
没有隐式的前向声明。交互设计在所有ML中都是明确的。唯一的困扰是,type
默认情况下定义是递归的,而let
绑定默认情况下是非递归的。
功能轮不存在。OCaml仍然没有标准stdlib,但是像Jane St's Core这样的第三方库提供了round
和朋友。
清单。List.map
仍不尾递归。我提交了补丁来修复此类严重的错误,并且不得不等了好几年才出现在发行版中。当然,列表仍然是一成不变的。所以应该如此。
速度。我相信大型多态变体的编译时间已经固定。
模式匹配。希望胜过现实。Lisp社区未能做到这一点。因此,我的第十条规则是:任何足够复杂的Lisp程序都包含OCaml模式匹配编译器的一半的即席,非正式指定且漏洞百出的实现。
例如:仍然不可能打印通用对象吗?
当他写信时,你不能简单地做:
print value
但是您可以从顶层调用漂亮的打印机作为库调用,并为其提供必要的类型信息。还有一个宏,您可以使用它来注释数据结构,以自动生成漂亮的打印机。
+
在整数,浮点数和复数上使用,但也可以定义自己的类型并添加重载+
以在您的类型上使用。这为Lisp或Haskell的简洁性和可读性提供了SML或OCaml的可预见的良好性能,实现了其他语言所没有的功能。