简体   繁体   English

ocaml 中的一元减号和一元波浪号减号运算符有什么区别?

[英]What are the differences between the unary minus and unary tilde minus operators in ocaml?

I'm learning OCaml, and the docs and books I'm reading aren't very clear on some things.我正在学习 OCaml,我正在阅读的文档和书籍在某些方面不是很清楚。

In simple words, what are the differences between简单来说,有什么区别

-10

and

~-10

To me they seem the same.在我看来,它们似乎是一样的。 I've encountered other resources trying to explain the differences, but they seem to explain in terms that I'm not yet familiar with, as the only thing I know so far are variables.我遇到过其他资源试图解释这些差异,但它们似乎用我还不熟悉的术语来解释,因为到目前为止我唯一知道的是变量。

In fact, - is a binary operator, so some expression can be ambigous: f 10 -20 is treated as (f 10) - 20 .事实上, -是一个二元运算符,因此某些表达式可能是模棱两可的: f 10 -20被视为(f 10) - 20 For example, let's imagine this dummy function:例如,让我们想象一下这个虚拟 function:

let f x y = (x, y)

If I want produce the tuple (10, -20) I naïvely would write something like that f 10 -20 which leads me to the following error:如果我想生成元组(10, -20)我天真地会写类似f 10 -20的东西,这会导致我出现以下错误:

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

because the expression is evaluated as (f 10) - 20 (so a substract over a function:!) so you can write the expression like this: f 10 (-20) , which is valid or f 10 ~-20 since ~- (and ~+ and ~-. ~+. for floats) are unary operators, the predecense is properly respected.因为表达式被评估为(f 10) - 20 (所以减去 function:!)所以你可以这样写表达式: f 10 (-20) ,这是有效的或f 10 ~-20因为~- (和~+~-. ~+.对于浮点数)是一元运算符,适当地尊重前置。

It is easier to start by looking at how user-defined unary (~-) operators work.通过查看用户定义的一元 (~-) 运算符的工作原理更容易开始。

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 }

In this situation, the unary operator - (and + ) is a shorthand for ~- (and ~+ ) when the parsing is unambiguous.在这种情况下,当解析明确时,一元运算符- (和+ )是~- (和~+ )的简写。 For example, defining -i with例如,定义-i

let mi = -i

works because this - could not be the binary operator - .有效,因为这-不能是二元运算符- Nevertheless, the binary operator has a higher priority than the unary - thus然而,二元运算符比一元运算符具有更高的优先级-因此

let wrong = Fun.id -i

is read as读作

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

In this context, I can either use the full form ~-在这种情况下,我可以使用完整的形式~-

let ok' = Fun.id ~-i

or add some parenthesis或添加一些括号

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

Going back to type with literals (eg integers, or floats), for those types, the unary + and - symbol can be part of the literal itself (eg -10 ) and not an operator.回到文字类型(例如整数或浮点数),对于这些类型,一元+-符号可以是文字本身的一部分(例如-10 )而不是运算符。 For instance redefining ~- and ~+ does not change the meaning of the integer literals in例如,重新定义~-~+不会改变 integer 文字的含义

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

This can be "used" to create some quite obfuscated expression:这可以“用来”创建一些相当模糊的表达式:

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

OCaml has two kinds of operators - prefix and infix . OCaml 有两种运算符——前缀和中 The prefix operators pre cede expressions and infix occur in between the two expressions, eg, in !foo we have the prefix operator !前缀运算符在表达式之前,中缀出现两个表达式之间,例如,在!foo我们有前缀运算符! coming before the expression foo and in 2 + 3 we have the infix operator + between expressions 2 and 3 .在表达式foo之前,在2 + 3中,我们在表达式23之间有中缀运算符+

Operators are like normal functions except that they have a different syntax for application (aka calling), whilst functions are applied to an arbitrary number of arguments using a simple syntax of juxtaposition, eg, f x1 x2 x3 x4 1 , operators can have only one (prefix) or two (infix) arguments.运算符类似于普通函数,只是它们具有不同的应用程序语法(也称为调用),而函数使用简单的并置语法应用于任意数量的 arguments,例如f x1 x2 x3 x4 1 ,运算符只能有一个(前缀)或两个(中缀)arguments。 Prefix operators are very close to normal functions, cf., fx and !x , but they have higher precedence (bind tighter) than normal function application.前缀运算符非常接近普通函数,参见fx!x ,但它们比普通 function 应用程序具有更高的优先级(绑定更紧密)。 Contrary, the infix operators, since they are put between two expressions, enable a more natural syntax, eg, x + y vs. (+) xy , but have lower precedence (bind less tight) than normal function application.相反,中缀运算符,因为它们放在两个表达式之间,所以可以实现更自然的语法,例如x + y(+) xy ,但比普通的 function 应用程序具有更低的优先级(绑定不那么紧)。 Moreover, they enable chaining several operators in a row, eg, x + y + z is interpreted as (x + y) + z , which is much more readable than add (add (xy) z) .此外,它们可以将多个运算符链接成一行,例如, x + y + z被解释为(x + y) + z ,这比add (add (xy) z)更具可读性。

Operators in OCaml distinguished purely syntactically. OCaml 中的运算符纯粹在语法上进行区分。 It means that the kind of an operator is fully defined by the first character of that operator, not by a special compiler directive, like in some other languages (ie, there is not infix + directive in OCaml).这意味着运算符的类型完全由该运算符的第一个字符定义,而不是像某些其他语言那样由特殊的编译器指令定义(即 OCaml 中没有中infix +指令)。 If an operator starts with the prefix-symbol sequence, eg, !如果运算符以前缀符号序列开头,例如! , ?@ , ~% , it is considered as prefix and if it starts with an infix-symbol then it is, correspondingly, an infix operator. , ?@ , ~% ,它被认为是前缀,如果它以中缀符号开头,那么它相应地是一个中缀运算符。

The - and -. --. operators are treated specially and can appear both as prefix and infix.运算符被特殊对待,可以作为前缀和中缀出现。 Eg, in 1 - -2 we have - occurring both in the infix and prefix positions.例如,在1 - -2我们有-出现在中缀和前缀位置。 However, it is only possible to disambiguate between the infix and the prefix versions of the - (and -. ) operators when they occur together with other operators (infix or prefix), but when we have a general expression, the - operator is treated as infix.然而,只有当它们与其他运算符(中缀或前缀)一起出现时,才可能在- (和-. )运算符的中缀和前缀版本之间消除歧义,但是当我们有一个通用表达式时, -运算符被处理作为中缀。 Eg, max 0 -1 is interpreted as (max 0) - 1 (remember that operator has lower precedence than function application, therefore when they two appear with no parentheses then functions are applied first and operators after that).例如, max 0 -1被解释为(max 0) - 1 (请记住,运算符的优先级低于 function 应用程序,因此当它们两个不带括号出现时,首先应用函数,然后应用运算符)。 Another example, Some -1 , which is interpreted as Some - 1 , not as Some (-1) .另一个例子, Some -1 ,它被解释为Some - 1 ,而不是Some (-1) To disambiguate such code, you can use either the parentheses, eg, max 0 (-1) , or the prefix-only versions, eg, Some ~-1 or max 0 ~-1 .要消除此类代码的歧义,您可以使用括号,例如max 0 (-1) ,或仅使用前缀的版本,例如Some ~-1max 0 ~-1

As a matter of personal style, I actually prefer parentheses as it is usually hard to keep these rules in mind when you read the code.就个人风格而言,我实际上更喜欢括号,因为在阅读代码时通常很难记住这些规则。


1) Purists will say that functions in OCaml can have only one argument and f x1 x2 x3 x4 is just ((f x1) x2) x3) x4 , which would be a totally correct statement, but a little bit irrelevant to the current discussion. 1)纯粹主义者会说 OCaml 中的函数只能有一个参数,而f x1 x2 x3 x4只是((f x1) x2) x3) x4 ,这是一个完全正确的说法,但与当前的讨论有点无关.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM