Compiler errors 为什么OCaml必须使用不同的浮点和int-literal语法?

Compiler errors 为什么OCaml必须使用不同的浮点和int-literal语法?,compiler-errors,ocaml,static-typing,Compiler Errors,Ocaml,Static Typing,OCaml对这两种语言都有不同的语法: 浮点运算与整数运算。浮点运算以点结束:+。。 浮点文本与整数文本。浮动以点结尾的文字:3。。 3 + 3;; -:int=6 3. +. 3. -:float=6。 3. + 3. 错误:此表达式的类型为float,但表达式的类型应为 int 我可以看到使用其中一个机制来消除歧义,但为什么总是需要两个呢? 例如,我可以看到这样一个案例。有时需要在文字的结尾,但不是为什么3+需要它。OCaml可以计算出我们需要浮点运算,因为我们说我们需要浮点运算 我正在寻找

OCaml对这两种语言都有不同的语法:

浮点运算与整数运算。浮点运算以点结束:+。。 浮点文本与整数文本。浮动以点结尾的文字:3。。 3 + 3;; -:int=6 3. +. 3. -:float=6。 3. + 3. 错误:此表达式的类型为float,但表达式的类型应为 int 我可以看到使用其中一个机制来消除歧义,但为什么总是需要两个呢? 例如,我可以看到这样一个案例。有时需要在文字的结尾,但不是为什么3+需要它。OCaml可以计算出我们需要浮点运算,因为我们说我们需要浮点运算


我正在寻找基于与其他语言功能交互的具体技术理由,而不是来自人体工程学的观点或论据。

每个功能都有一个类型,这就是OCaml语法的主要原因。如果您传递了一个不合适的参数,编译器将拒绝您的代码并产生错误

这似乎很明显,但在任何函数中都是如此,包括基本的数学运算符:名为+的函数。具有以下类型:

val+:浮动->浮动->浮动 就这些。如果给出的是int而不是float,编译器会告诉您代码是错误的。OCaml什么都没有。编译器只需使用函数签名检查参数是否有效。不是吗?错误

您可能会认为这一点是错误的,因为任何C编译器都会接受您的代码行,并按照预期的结果生成一个浮点。但这是另一种语言,即使这可以工作,在OCaml中也不允许这样做。你不能逃避这种类型

问题很清楚:每个函数都是由参数的类型定义的,您不能给出一个多类型的参数

这允许编译器轻松地优化代码,但您必须明确地将参数转换为函数签名所期望的参数


实际上不会,因为OCaml中int的内存表示形式与C中的int不完全相同,但这是另一个主题,每个函数都有一个类型,这就是OCaml语法的主要内容。如果您传递了一个不合适的参数,编译器将拒绝您的代码并产生错误

这似乎很明显,但在任何函数中都是如此,包括基本的数学运算符:名为+的函数。具有以下类型:

val+:浮动->浮动->浮动 就这些。如果给出的是int而不是float,编译器会告诉您代码是错误的。OCaml什么都没有。编译器只需使用函数签名检查参数是否有效。不是吗?错误

您可能会认为这一点是错误的,因为任何C编译器都会接受您的代码行,并按照预期的结果生成一个浮点。但这是另一种语言,即使这可以工作,在OCaml中也不允许这样做。你不能逃避这种类型

问题很清楚:每个函数都是由参数的类型定义的,您不能给出一个多类型的参数

这允许编译器轻松地优化代码,但您必须明确地将参数转换为函数签名所期望的参数

实际上不会,因为OCaml中int的内存表示形式与C中的int不完全相同,但这是另一个主题,简而言之,这是因为+。和+以及1和1。表示不同的值,尽管它们看起来很相似。这些值具有不同的类型、不同的表示和不同的语义。使+和1在不同上下文中工作相同的语言特性称为ad-hoc多态性,它不存在于OCaml中。OCaml并不是试图从程序的文本表示及其类型推断您将要使用的值,而是根据您正在使用的值以及如何使用它们来推断您的程序的类型。ML wrt的一个重要区别是,其他一些语言会以另一种方式移动,即它们具有用户指定的类型,然后推断与该类型匹配的正确值,并检查这些值是否正确使用。在ML中,输入是程序,输出是该程序的类型,a用于证明程序类型正确,在运行时不会有任何类型错误,b用于生成本机代码和性能代码,并删除所有推断类型。了解OCaml中的类型推断并不是一个方便实用程序,当可以像在Scala中的C++自动或本地类型推断中那样推断类型时,可以省略这些类型,这一点也很重要。相反,它是编译过程和语言语义中的主要步骤,因为OCaml必须能够推断任何程序的类型。我们偶尔在OCaml程序中编写的类型仅用作约束,从不作为inp uts。此外,类型注释永远不会改变程序的行为。好吧,除非GADTs起作用,但这是一个完全不同的故事

为了更深入的了解,我们应该回顾一下OCaml下面的类型推断算法是语法驱动的和声明性的。语法驱动意味着程序语法完全定义了该程序的类型。此外,该算法确保如果类型存在,即程序类型良好,则该推断类型是唯一的和主要的。也就是说,不存在表示此程序的其他类型,或者所有其他类型都是推断类型的实例。声明性的意思是如何将类型分配给程序的规则是用。该算法将程序正式转换为类型,从而实现/确保计算机程序和数学证明之间的对应关系。这使我们能够谈论程序的正确性,反之亦然,谈论真理的正确性,即用程序证明我们的定理是正确的。这让我们回到了OCaml/ML的历史,它最初是一种用于可计算函数逻辑定理证明的元语言ML

既然我们同意我们不想失去这种语言的重要属性,那么问题仍然悬而未决,为什么我们不能实现语法驱动和可声明的即席多态性呢。事实上,我们可以,比如,哈斯克尔有一个。还有一些关于添加到OCaml的工作。但这一切都伴随着权衡,最终它将是一种完全不同的语言。到目前为止,在OCaml中,每个值都有一个类型或一个类型方案,而在OCaml运行时系统中没有一个类型将代表一个用于整数和浮点运算的+运算符

话虽如此,如果OCaml不说您可以定义自己的+运算符,该运算符的类型为number->number->number,其中数字是一个存在类型number=Num:'a typeid*'a->number,其中每个typeid都有一个单独的操作表存储在某个隐藏的哈希表中,这将是不诚实的。但这将是动态类型,看看typeid是如何包装在每个值中的,它与静态类型完全不同,在我们的示例中,这个+函数在运行时可能会失败,我们的键入规则不是声明性的,而是+运算符实现的固有规则。简而言之,这是因为+。和+以及1和1。表示不同的值,尽管它们看起来很相似。这些值具有不同的类型、不同的表示和不同的语义。使+和1在不同上下文中工作相同的语言特性称为ad-hoc多态性,它不存在于OCaml中。OCaml并不是试图从程序的文本表示及其类型推断您将要使用的值,而是根据您正在使用的值以及如何使用它们来推断您的程序的类型。ML wrt的一个重要区别是,其他一些语言会以另一种方式移动,即它们具有用户指定的类型,然后推断与该类型匹配的正确值,并检查这些值是否正确使用。在ML中,输入是程序,输出是该程序的类型,a用于证明程序类型正确,在运行时不会有任何类型错误,b用于生成本机代码和性能代码,并删除所有推断类型。了解OCaml中的类型推断并不是一个方便实用程序,当可以像在Scala中的C++自动或本地类型推断中那样推断类型时,可以省略这些类型,这一点也很重要。相反,它是编译过程和语言语义中的主要步骤,因为OCaml必须能够推断任何程序的类型。我们偶尔在OCaml程序中编写的类型仅用作约束,从不作为输入。此外,类型注释永远不会改变程序的行为。好吧,除非GADTs起作用,但这是一个完全不同的故事

为了更深入的了解,我们应该回顾一下OCaml下面的类型推断算法是语法驱动的和声明性的。语法驱动意味着程序语法完全定义了该程序的类型。此外,该算法确保如果类型存在,即程序类型良好,则该推断类型是唯一的和主要的。也就是说,不存在表示此程序的其他类型,或者所有其他类型都是推断类型的实例。声明性的意思是如何将类型分配给程序的规则是用。该算法将程序正式转换为类型,从而实现/确保计算机程序和数学证明之间的对应关系。这使我们能够谈论程序的正确性,反过来说,谈论真相c 正确性,即用程序证明我们的定理是正确的。这让我们回到了OCaml/ML的历史,它最初是一种用于可计算函数逻辑定理证明的元语言ML

既然我们同意我们不想失去这种语言的重要属性,那么问题仍然悬而未决,为什么我们不能实现语法驱动和可声明的即席多态性呢。事实上,我们可以,比如,哈斯克尔有一个。还有一些关于添加到OCaml的工作。但这一切都伴随着权衡,最终它将是一种完全不同的语言。到目前为止,在OCaml中,每个值都有一个类型或一个类型方案,而在OCaml运行时系统中没有一个类型将代表一个用于整数和浮点运算的+运算符

话虽如此,如果OCaml不说您可以定义自己的+运算符,该运算符的类型为number->number->number,其中数字是一个存在类型number=Num:'a typeid*'a->number,其中每个typeid都有一个单独的操作表存储在某个隐藏的哈希表中,这将是不诚实的。但这将是动态类型查看typeid是如何包装在每个值中的,它与静态类型完全不同,静态类型在程序运行之前为您提供了保证在我们的示例中,此+函数可能在运行时失败,并且我们的类型规则不是声明性的,而是+运算符实现的固有规则