我们知道,不少编程语言都支持自定义操作符,特别是对于数学相关领域的应用来说,自定义类型上的操作符可以大大简化代码,提高程序可读性。对于F#来说,支持全局的自定义操作符和附属于特定类型的操作符。这里需要注意的就是,全局自定义操作符需要慎用,他可能会覆盖默认的操作符。
下面我们定义一个全局操作符,具体示例如下:
//全局操作符,覆盖默认的letinline (+)(a : float)(b : float) =2.*a*b ;;
在F#交互环境下(;;为结束标志),此示例执行如下:
此时,输入 2. + 3. 的计算结果为12.0 。其中的2.是2.0的简写,代表float类型。另外,如果此时输入2 + 3 则提示错误,因为此为int类型,而定义的操作符参数类型是float,不兼容。
还有一类就是对于自定义类型上的自定义操作符。这种比较常见,下面给出一个自定义复数类型,并给出自定义操作符的示例。
moduleYdMath//https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/operator-overloadingtypeComplex= { Real : floatImaginary : float } staticmember (+) (f1 : Complex, f2 : Complex) =letcr=f1.Real+f2.Realletci=f1.Imaginary+f2.Imaginary {Real=cr ; Imaginary=ci} staticmember (-) (f1 : Complex, f2 : Complex) =letcr=f1.Real-f2.Realletci=f1.Imaginary-f2.Imaginary {Real=cr ; Imaginary=ci} overridethis.ToString() =if (this.Imaginary=0.) thenthis.Real.ToString() elsethis.Real.ToString() +"+"+this.Imaginary.ToString()+"i"
从数学上来说,复数(Complex)具有一个实部(Real)和一个虚部(Imaginary) ,这里的话,用float类型来代表每个部分的数值类型。其中的static member定义了一个静态成员方法,但它的函数名是一个操作符,可实现自定义操作符功能。这里简单的定义了一个复数的加法和减法操作。并override重写了ToString方法。最后,我们用如下代码段进行自定义操作符测试:
letc1= { Real=3. ; Imaginary=5. } letc2= { Real=2. ; Imaginary=3. } letc3=c1+c2letc4=c1-c2printfn"(%s) + (%s) = %s" (c1.ToString()) (c2.ToString()) (c3.ToString()) printfn"(%s) - (%s) = %s" (c1.ToString()) (c2.ToString()) (c4.ToString())
运行此示例,结果如下:
(3+5i) + (2+3i) =5+8i(3+5i) - (2+3i) =1+2i
最后,再给出一个根据官方文档示例修改的自定义操作符:
letrechcfab=ifa=0.thenbelifa<bthenhcfa (b-a) elsehcf (a-b) b//分数typeFract= { fz : float//分子fm : float//分母 } staticmember (+) (f1 : Fract, f2 : Fract) =letfz=f1.fz*f2.fm+f2.fz*f1.fmletfm=f1.fm*f2.fmletcf=hcffzfm { fz=fz/cf; fm=fm/cf } staticmember (-) (f1 : Fract, f2 : Fract) =letfz=f1.fz*f2.fm-f2.fz*f1.fmletfm=f1.fm*f2.fmletcf=hcffzfm { fz=fz/cf; fm=fm/cf } staticmember (*) (f1 : Fract, f2 : Fract) =letfz=f1.fz*f2.fzletfm=f1.fm*f2.fmletcf=hcffzfm { fz=fz/cf; fm=fm/cf } staticmember (/) (f1 : Fract, f2 : Fract) =letfz=f1.fz*f2.fmletfm=f2.fz*f1.fmletcf=hcffzfm { fz=fz/cf; fm=fm/cf } overridethis.ToString() =if (this.fm=1.) thenthis.fz.ToString() elsethis.fz.ToString() +"/"+this.fm.ToString()
执行测试代码示例如下:
letf1= { fz=2.; fm=5.} letf2= { fz=1.; fm=6.} letf=f1+f2printfn"(%s) + (%s) = %s" (f1.ToString()) (f2.ToString()) (f.ToString()) letf=f1-f2printfn"(%s) - (%s) = %s" (f1.ToString()) (f2.ToString()) (f.ToString()) letf=f1*f2printfn"(%s) * (%s) = %s" (f1.ToString()) (f2.ToString()) (f.ToString()) letf=f1/f2printfn"(%s) / (%s) = %s" (f1.ToString()) (f2.ToString()) (f.ToString())
执行示例结果如下:
(2/5) + (1/6) =17/30(2/5) - (1/6) =7/30(2/5) * (1/6) =1/15(2/5) / (1/6) =12/5