F# 编程/运算符重载
外观
< F# 编程
F#:运算符重载 |
运算符重载允许程序员为 F# 中的默认运算符提供新行为。在实践中,程序员重载运算符以提供一种简化的语法,用于可以数学组合的对象。
你已经使用过运算符了
let sum = x + y
这里 +
是使用数学加法运算符的示例。
运算符是具有特殊名称的函数,用括号括起来。它们必须定义为静态类成员。以下是在复数上声明 +
运算符的示例
type Complex =
{ Re: double
Im: double }
static member ( + ) (left: Complex, right: Complex) =
{ Re = left.Re + right.Re; Im = left.Im + right.Im }
在 FSI 中,我们可以按如下方式添加两个复数
> let first = { Re = 1.0; Im = 7.0 };;
val first : Complex
> let second = { Re = 2.0; Im = -10.5 };;
val second : Complex
> first + second;;
val it : Complex = {Re = 3.0;
Im = -3.5;}
除了重载现有的运算符之外,还可以定义新的运算符。自定义运算符的名称只能是以下一个或多个字符
!%&*+-./<=>?@^|~
F# 支持两种类型的运算符:中缀运算符和前缀运算符。
中缀运算符接受两个参数,运算符出现在两个参数之间(即 arg1 {op} arg2
)。我们可以使用以下语法定义自己的中缀运算符
let (op) arg1 arg2 = ...
除了数学运算符之外,F# 还将其库中定义了许多中缀运算符,例如
let inline (|>) x f = f x
let inline (::) hd tl = Cons(hd, tl)
let inline (:=) (x : 'a ref) value = x.contents <- value
假设我们正在编写一个执行大量正则表达式匹配和替换的应用程序。我们可以通过定义自己的运算符来使用 Perl 风格的运算符匹配文本,如下所示
open System.Text.RegularExpressions
let (=~) input pattern =
Regex.IsMatch(input, pattern)
let main() =
printfn "cat =~ dog: %b" ("cat" =~ "dog")
printfn "cat =~ cat|dog: %b" ("cat" =~ "cat|dog")
printfn "monkey =~ monk*: %b" ("monkey" =~ "monk*")
main()
该程序输出以下内容
cat =~ dog: false cat =~ cat|dog: true monkey =~ monk*: true
前缀运算符接受一个参数,该参数出现在运算符的右侧({op}argument
)。你已经看到 !
运算符是如何为 ref 单元格定义的
type 'a ref = { mutable contents : 'a }
let (!) (x : 'a ref) = x.contents
假设我们正在编写一个数字处理应用程序,我们想要定义一些在数字列表上工作的运算符。我们可能会在 fsi 中定义一些前缀运算符,如下所示
> let ( !+ ) l = List.reduce ( + ) l
let ( !- ) l = List.reduce ( - ) l
let ( !* ) l = List.reduce ( * ) l
let ( !/ ) l = List.reduce ( / ) l;;
val ( !+ ) : int list -> int
val ( !- ) : int list -> int
val ( !* ) : int list -> int
val ( !/ ) : int list -> int
> !* [2; 3; 5];;
val it : int = 30
> !+ [2; 3; 5];;
val it : int = 10
> !- [2; 3; 7];;
val it : int = -8
> !/ [100; 10; 2];;
val it : int = 5