我正在学习Jason Hickey's Introduction to Objective Caml。
关于重新定义中缀运算符的问题。
所以在书中,有这样一段:
# let (+) = ( * )
and (-) = (+)
and ( * ) = (/)
and (/) = (-);;
val + : int > int > int = <fun>
val - : int > int > int = <fun>
val * : int > int > int = <fun>
val / : int > int > int = <fun>
# 5 + 4 / 1;;
-: **int = 15**
首先,这些重新定义是如何工作的?
对我而言,似乎函数在一种无限循环中运行,因为所有操作似乎都被重新定义和连接。
例如,如果我1+2
,那么它将是1 * 2
,从( * ) = (/)
起,它将是1 / 2
,然后是(/) = (-)
,那么它将是1-2
,依此类推。 我是对的吗?
其次,5 + 4 / 1
的结果是否为15
,即使这些功能在重新定义中只执行了一步?
因此,假设重新定义将进一步执行,即1 + 2
只会1 * 2
而不再有变换,因此5 + 4 / 1
应为5 * 4 -1
,对吧?然后答案是19
。 我说错了吗?
答案 0 :(得分:6)
对我而言,似乎功能正在以某种无限的方式运行 循环,因为所有操作似乎都被重新定义和连接。
实际上,它只是同时重新定义中缀运算符(使用and
关键字)。你看到的是不递归定义。在OCaml中,使用 let rec 进行递归定义(正如您可能已经知道的那样)。
对于问题的第二部分,我认为这是运算符优先级的问题。请注意,原始表达式5 + 4 / 1
实际上是5 + (4/1)
,遵循算术运算符的常规优先规则。所以,我认为转换只是保留了这种绑定(有点)。你得到5 * (4 - 1) = 15
。
答案 1 :(得分:3)
关键观察(恕我直言)是(+)
由( * )
的预先存在的定义定义,而不是由稍后出现几行的定义。同样,( * )
由预先存在的定义(/)
定义。正如Asiri所说,这是因为使用let
而不是let rec
。
在OCaml中,优先级和关联性在运算符中是固有的,并且不能通过定义来更改。优先级和关联性由运算符的第一个字符决定。
如果查看Section 6.7 of the OCaml Manual中的运算符优先级和关联性表,您将看到所有条目都是为“以字符X开头的运算符”定义的。