3

我正在学习Jason Hickey 的 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我对么?

4

2 回答 2

6

对我来说,这些函数似乎在一种无限循环中运行,因为所有操作似乎都重新定义并相互关联。

不是真的,它只是同时重新定义中缀运算符(使用and关键字)。你看到的不是递归定义。在 OCaml 中,递归定义是用let rec进行的(你可能已经知道了)。

对于问题的第二部分,我认为这是operator priority的问题。请注意,原始表达式5 + 4 / 1实际上5 + (4/1)遵循算术运算符的通常优先规则。所以,我认为转换只是保留了这种绑定(有点)。你得到了5 * (4 - 1) = 15

于 2012-12-03T15:31:59.473 回答
3

关键观察 (恕我直言) 是(+)由 的预先存在的定义定义的( * ),而不是由几行之后出现的定义定义的。同样,( * )is 由 的预先存在的定义定义(/)。正如 Asiri 所说,这是因为使用了let而不是let rec.

这也是事实,在 OCaml 中,优先级和关联性是运算符固有的,不能通过定义进行更改。优先级和关联性由运算符的第一个字符决定。

如果您查看OCaml 手册 6.7 节中的运算符优先级和关联性表,您会看到所有条目都是为“以字符 X 开头的运算符”定义的。

于 2012-12-03T15:58:31.783 回答