【问题标题】:Error: Unexpected infix operator in expression, about a successfully compiled prefix operator错误:表达式中出现意外的中缀运算符,关于成功编译的前缀运算符
【发布时间】:2017-01-13 08:09:10
【问题描述】:

玩弄中缀运算符后,我对以下内容感到惊讶:

let (>~~~) = function null -> String.Empty | s -> s  // compiles fine, see screenshot
match >~~~ input with .... // error: Unexpected infix operator in expression

和:

更改 prefix 运算符的第一个字符(例如更改为 !~~~)修复它。我得到一个错误,即 infix 运算符是意外的,这很奇怪。悬停显示定义为string -> string

我对这个错误并不感到惊讶,F# 要求 (iirc) 前缀运算符的第一个字符本身必须是预定义的前缀运算符之一。但是为什么它编译得很好,而我使用它时,编译器会报错?

更新:当我在运算符定义中使用无效字符时,F# 编译器似乎知道在其他情况下就好了,它说 “无效的运算符定义。前缀运算符定义必须使用有效的前缀运算符名称。”

【问题讨论】:

  • 如果你也把>~~~放在匹配表达式的括号内呢?
  • @s952163: 很简单,但是,确实有效。但是,如果您必须添加括号,它首先会破坏创建运算符的宏伟想法。
  • 是的......不幸的是。我不知道为什么。这确实是一个非常有趣的案例。
  • 在F#brackets are used to control precedence中,自定义运算符的优先级为controlled by a pre-defined table。所以> 的优先级不同于!
  • @s952163 给定let (~+.) x = -x,你实际上可以写成+. 10~ 符号用于区分以+ 开头的二元运算符和以+ 开头的一元运算符。

标签: f# operator-overloading prefix-operator infix-operator


【解决方案1】:

F# 中自定义运算符的规则非常严格 - 因此即使您可以定义自定义运算符,也有很多关于它们的行为方式的规则,您无法更改这些规则。特别是:

  • 只有部分运算符(主要是带有!~ 的运算符)可以用作前缀运算符。使用~,您还可以重载一元运算符+-~~~,因此如果您定义一个名为~+. 的运算符,则可以将其用作例如+. 42
  • 其他运算符(包括以> 开头的运算符)只能用作中缀。您可以使用括号将任何运算符转换为普通函数,这就是为什么例如(+) 1 2 有效。
  • ? 符号很特殊(用于动态调用),不能作为自定义运算符的第一个符号出现。

我认为最直观的思考方式是自定义运算符的行为类似于标准 F# 运算符,但您可以在标准运算符名称后添加其他符号。

【讨论】:

  • 谢谢。是的,我知道这些规则,但是可以看出,这些规则可以被弯曲(只要在调用中使用括号,就可以定义带有中缀运算符首字符的后缀运算符)。并且错误谈到了中缀运算符,但没有抱怨声明。为什么像let (>~) = function null -> true | _ -> false 这样的东西不违法呢?
  • @Abel 这并不违法,因为你仍然可以通过括号使用它(这不是违反规则,而是将运算符视为普通函数)。这也可能不是非法的,因为您可以拥有 int -> 'a 类型的泛型运算符,它可以是一元或二元,具体取决于泛型实例化 - 所以在 F# 中说什么是一元函数并不容易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 2022-01-23
  • 2011-08-30
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
相关资源
最近更新 更多