【问题标题】:What are the differences between the unary minus and unary tilde minus operators in ocaml?ocaml 中的一元减号和一元波浪号减号运算符有什么区别?
【发布时间】:2021-03-17 20:28:44
【问题描述】:

我正在学习 OCaml,我正在阅读的文档和书籍在某些方面不是很清楚。

简单来说,两者有什么区别

-10

~-10

在我看来,它们似乎是一样的。我遇到过其他资源试图解释这些差异,但它们似乎用我还不熟悉的术语来解释,因为到目前为止我唯一知道的是变量。

【问题讨论】:

    标签: operators ocaml


    【解决方案1】:

    事实上,- 是一个二元运算符,所以某些表达式可能是模棱两可的:f 10 -20 被视为(f 10) - 20。例如,让我们想象一下这个虚拟函数:

    let f x y = (x, y)
    

    如果我想生成元组(10, -20),我会天真地写类似f 10 -20 的东西,这会导致我出现以下错误:

    # f 10 -20;;
    Error: This expression has type 'a -> int * 'a
           but an expression was expected of type int
    

    因为表达式被评估为(f 10) - 20(所以是一个函数的减法!!)所以你可以这样写表达式:f 10 (-20),这是有效的或f 10 ~-20,因为~-(和@987654332 @ 和 ~-. ~+. 用于浮点数)是一元运算符,正确遵守前置。

    【讨论】:

    • 事实上,- 并不总是二进制的,例如,在1 - -2 中,- 同时出现为一元和二进制(OCaml 用语中的前缀或中缀)
    • 感谢您的澄清。你显然是对的,但我很想给出一个非常直截了当的答案。
    【解决方案2】:

    从查看用户定义的一元 (~-) 运算符的工作原理开始会更容易。

    type quaternion = { r:float; i:float; j:float; k:float }
    let zero = { r = 0.; i = 0.; j = 0.; k = 0. }
    let i = { zero with i = 1. }
    let (~-) q = { r = -.q.r; i = -.q.i; j = -. q.j; k = -. q.k }
    

    在这种情况下,当解析明确时,一元运算符-(和+)是~-(和~+)的简写。例如,用

    定义-i
    let mi = -i
    

    有效,因为这个- 不能是二元运算符-。 尽管如此,二元运算符的优先级高于一元-,因此

    let wrong = Fun.id -i
    

    读作

    let wrong = (Fun.id) - (i)
    

    在这种情况下,我可以使用完整形式 ~-

    let ok' = Fun.id ~-i
    

    或添加一些括号

    let ok'' = Fun.id (-i)
    

    回到文字类型(例如整数或浮点数),对于这些类型,一元 +- 符号可以是文字本身的一部分(例如 -10),而不是运算符。例如重新定义 ~-~+ 不会改变整数文字的含义

    let (~+) = ()
    let (~-) = ()
    let really = -10
    let positively_real = +10
    

    这可以“用来”创建一些相当模糊的表达式:

    let (~+) r = { zero with r }
    let (+) x y = { r = x.r +. y.r; i = x.i +. y.i; k = x.k +. x.k; j =x.k +. y.j  }
    let ( *. ) s q = { r = s *. q.r; i = s *. q.i; j = s *. q.j; k = s *. q.k }
    let this_is_valid x = +x + +10. *. i
    

    【讨论】:

      【解决方案3】:

      OCaml 有两种operators - 前缀中缀。前缀运算符 precede 表达式和中缀出现在两个表达式之间 in,例如,在!foo 中,我们在表达式 foo 之前有前缀运算符 !2 + 3 中,我们在表达式23 之间有中缀运算符+

      运算符与普通函数类似,只是它们具有不同的应用程序语法(也称为调用),而函数使用简单的并置语法应用于任意数量的参数,例如f x1 x2 x3 x41 sup>,运算符只能有一个(前缀)或两个(中缀)参数。前缀运算符非常接近普通函数,参见f x!x,但它们比普通函数应用具有更高的优先级(绑定更紧密)。相反,中缀运算符,因为它们放在两个表达式之间,所以可以实现更自然的语法,例如,x + y(+) x y,但比普通函数应用程序具有更低的优先级(绑定不那么紧)。此外,它们可以将多个运算符串联成一行,例如,x + y + z 被解释为(x + y) + z,这比add (add (x y) z) 更具可读性。

      OCaml 中的运算符纯粹在语法上进行区分。这意味着运算符的类型完全由该运算符的第一个字符定义,而不是由特殊的编译器指令定义,就像在其他一些语言中那样(即 OCaml 中没有 infix + 指令)。如果运算符以prefix-symbol 序列开头,例如!?@~%,则将其视为前缀,如果以infix-symbol 开头,则相应地是中缀运算符。

      --. 运算符被特殊处理,可以作为前缀和中缀出现。例如,在1 - -2 中,- 出现在中缀和前缀位置。但是,只有当-(和-.)运算符与其他运算符(中缀或前缀)一起出现时,才有可能消除中缀和前缀版本的歧义,但是当我们有一个通用表达式时,@ 987654349@ 运算符被视为中缀。例如,max 0 -1 被解释为(max 0) - 1(请记住,运算符的优先级低于函数应用程序,因此当它们两个不带括号出现时,首先应用函数,然后应用运算符)。另一个例子,Some -1,它被解释为Some - 1,而不是Some (-1)。要消除此类代码的歧义,您可以使用括号,例如 max 0 (-1),或仅使用前缀的版本,例如 Some ~-1max 0 ~-1

      就个人风格而言,我实际上更喜欢括号,因为在阅读代码时通常很难记住这些规则。


      1) 纯粹主义者会说 OCaml 中的函数只能有一个参数,而 f x1 x2 x3 x4 只是 ((f x1) x2) x3) x4,这是一个完全正确的说法,但与当前的说法有点无关讨论。

      【讨论】:

        猜你喜欢
        • 2012-03-17
        • 2021-11-15
        • 2016-08-24
        • 2019-01-01
        相关资源
        最近更新 更多