OCaml批评:它仍然有效吗?


15

我是OCaml的新手。我最近偶然发现此页面,列出了对OCaml的大量批评。

看到页面很旧(2007年):今天列出的哪些项目符号仍然正确?例如:仍然不可能打印通用对象吗?

我想明确指出,我不是要讨论其中表达的意见。我在问列出的信息(例如整数无警告溢出)是否仍然适用于OCaml的最新版本


5
我投票关闭此问题为离题,因为meta.programmers.stackexchange.com/questions/6417/…–
Philipp

3
有一个可以修复这些问题的叉子:tryfsharp.org

7
当然,您链接的那篇文章中的观点是正确的,但是这些批评是否与您相关,则完全不同。请注意,作者来自Common Lisp背景,因此具有Lispish值。如果您使用OCaml的另一种方法而不是将它与Lisp进行比较(例如“ OCaml是Haskell的凡人”或“如果C是一种功能语言,那么您将拥有OCaml”),您会发现它更加令人满意。尽管存在所有缺陷,OCaml是一种很棒的语言,但是我还是鼓励您尝试一下。
amon 2015年

5
据我所知,无法检测到硬件中的整数溢出,因此您需要在所有位置插入运行时检查以进行检测;但基于性能,作者拒绝使用“ bignum”!关于静态打字的抱怨等于说安全带不好,因为您可能认为自己不会死于车祸。关于模块不变性的抱怨是,他想修补问题-一种反模块化且容易出错的做法。“小型动物园”与类型推断无关。显然他的偏见在哪里
2015年

2
@Doval:当然,您可以检测到硬件溢出。 但是,处理它是软件问题。
梅森惠勒

Answers:


13

本文在几个地方讨论:

总结一下:是的,OCaml不是Lisp,不是,它不是完美的(这意味着什么?)。我认为博客文章中提到的观点与O'Caml的日常程序员无关。

学习过O'Caml之后,我认为这是一种有趣的语言,可以帮助您构建甚至都不敢用C / C ++ / Java编写的程序:例如,看看 Frama-C

关于O'Caml的最新描述,我建议您阅读其功能:该语言促进了强大的静态类型检查技术,该技术使实现专注于产生高性能但安全的运行时。

重要提示:我不是OCaml专家:如果您是其中的一员,并且看到我写的东西严重错误,请纠正我。我将相应地编辑此帖子。

静态类型检查

  • 错误的安全感

    这是事实,但显而易见。

    静态类型为您提供了您可以信任的程序属性子集的证明。除非您接受所有正式的程序,否则普通(非玩具)程序将受到编程错误错误的影响,这些错误错误只能在运行时才能看到。

    到那时,可以应用动态检查技术:OCaml编译器具有用于生成带有调试信息的可执行文件的标志,依此类推……或者,它可以生成盲目的信任程序员并尽可能擦除类型信息的代码。希望使用健壮程序的程序员应明确实现动态检查。

    同样的情况适用于例如Common Lisp,但相反:首先是动态类型,其次是可选的类型声明和编译器指令。

  • 几种基本类型

    仍然适用:核心语言没有改变(或没有太大变化)。

  • 无声整数溢出

    在大多数语言中,这是整数溢出是由人工检查的规范。我不知道有哪个库会进行类型检查操作以验证是否会发生溢出。

  • 模块不变性

    1. 作者提到了函子,但我看不到他的示例无法实现。阅读https://realworldocaml.org的“ 头等舱模块”一章,似乎可以将这些模块用于组成构建新模块。当然,修改现有模块需要修改源代码,但同样,这在编程语言中并不罕见。

    2. “从语义上讲,函数是在线编译的”

    上面的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会很有用,看到更多语言中缺少它确实很痛苦。以下是一些选项:

    1. 改善OCaml中的异常管理
    2. 扩展OCaml语法
  • 地方

    我认为OCaml中不存在通用引用。

轻微语言浮躁

  • 记录字段命名地狱

    是的,但是您应该使用模块:

    1. 两个记录的两个字段在OCaml中具有相同的标签
    2. 解析字段名称
  • 句法

    仍然适用(但实际上,这只是语法)。

  • 没有多态

    仍然适用,但不知何故有些人更喜欢 Lisp的数字塔(我不知道为什么)。我想它有助于类型推断。

  • 功能集不一致

    请参阅“ 包含OCaml电池”项目。特别是 BatArray,例如map2for数组。

  • 没有动态变量

    可以实现:

    1. http://okmij.org/ftp/ML/dynvar.txt
    2. http://okmij.org/ftp/ML/index.html#dynvar
  • 可选〜参数很烂

    受语言限制,您不能在Common Lisp中混合使用可选参数和关键字参数。这是不是很烂?(当然,这可以通过宏进行更改(例如参见我的回答))。有关O'Caml中的可选参数和命名参数,请参见O'Caml的文档

  • 部分参数应用程序不一致

    我不认为这在实践中真的很烦人。

  • 算术的可读性

    它成立了,但是您可以根据需要使用R或Python解决数值问题。

  • 沉默的名字冲突解决

    仍然适用,但是请注意,这已经有据可查。

  • 没有对象输入/输出

    仍然适用。

实施库

这些每天都在变化:没有确切的答案。

最后,

“即使您认为OCaml很烂,并且您不打算使用它,也应该尝试OCaml(或者更好的是,Haskell)。没有它,您的计算机科学教育就不完整,就像没有Lisp和C(或,更好的是,大会)曝光。”

...仍然适用。


谢谢,我将看看这些链接,但我并不是真的在问那些观点是否合理。我问事实是否仍然成立。例如:有没有办法打印出任何代数数据类型?整数无警告溢出仍然准确吗?今天是否有一种方法可以对文件进行操作并处理它们,而不必每次都要编写样板来处理因错误而关闭文件?
Andrea

@Andrea我编辑了答案。
coredump

1
“ ...有些人更喜欢Lisp的数字塔(我不知道为什么)。我认为它有助于类型推断。” 答对了。SML和OCaml的类型系统要求每个表达式只有一个类型。SML数学运算符的重载是该语言内置的一个例外。Haskell也是如此。启用这种重载是类型类背后的动机。问题是每种类型只能有一个类型类实例。您也不能盲目地将整数转换为大小相等的浮点数-64位浮点数只有54位精度。
2015年

@Doval像为球拍键入数字塔呢?我们是否可以想象一个OCaml库将利用类型类或广义代数数据类型(GADT)来提供多态数学运算符?关于转换:并非所有的操作都是可能的,但是某些可以并且可以被键入。
coredump

2
@Doval:“回复:多态数学运算符,如果不实现Haskell的类型类,我认为是没有办法的”。F#具有不带类型类的多态数学运算符。
乔恩·哈罗普

7

看到页面很旧(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

但是您可以从顶层调用漂亮的打印机作为库调用,并为其提供必要的类型信息。还有一个宏,您可以使用它来注释数据结构,以自动生成漂亮的打印机。


模式匹配:OCaml源代码optima都引用同一篇论文:“优化模式匹配”。我要说的是,“临时”,“臭虫缠身”或“非正式指定”都不能在这里实际应用。“ F#为这个问题提供了一个很好的解决方案”:如果可能的话,我真的很想看到有关此问题的更多详细信息。答案是好的,但是在谈论时骂人cons会给出不好的语气(原始文章是一团糟,但您无需从中复制出来)。
coredump

2
@coredump:“如果可能的话,我真的希望看到更多细节”。F#在某些运算符和函数上具有用户定义的即席多态性。因此,您可以+在整数,浮点数和复数上使用,但也可以定义自己的类型并添加重载+以在您的类型上使用。这为Lisp或Haskell的简洁性和可读性提供了SML或OCaml的可预见的良好性能,实现了其他语言所没有的功能。
乔恩·哈罗普

@coredump:“ OCaml源代码和optima都引用同一篇论文”。该论文中描述的技术完全基于ML类型系统。Lisp没有的类型系统。Optima不能并且不能做该论文中描述的很多事情。只需查看第4.2节“使用穷举信息”。Lisp中没有穷举性信息,因为没有变体类型。例如,OCaml根据叶子的数量在嵌套跳转或调度表之间进行选择,但该信息在Lisp中是未知的。
乔恩·哈罗普

Lisp和OCaml设计用于不同的事物(例如,动态性,基于图像的编程)。但是Lisp 具有不同于Hindley-Milner的类型系统,实现在编译过程中利用它。通过本文4.2节中的示例查看此SBCL会议。穷举性已经由编译器根据类型推断和声明进行检查。Optima可以为编译时宏扩展(或SBCL VOP)添加特定于实现的代码,以具有其他策略,但是这样做的动机不足。
coredump

这如何应用于用户定义的代数数据类型?
乔恩·哈罗普
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.