F Sharp Programming/Operator Overloading

Previous: Exception Handling Index Next: Classes
F# : Operator Overloading

Operator overloading allows programmers to provide new behavior for the default operators in F#. In practice, programmers overload operators to provide a simplified syntax for objects which can be combined mathematically.

Using Operators edit

You've already used operators:

let sum = x + y

Here + is example of using a mathematical addition operator.

Operator Overloading edit

Operators are functions with special names, enclosed in brackets. They must be defined as static class members. Here's an example on declaring + operator on complex numbers:

type Complex =
    {   Re: double
        Im: double }
    static member ( + ) (left: Complex, right: Complex) =
        { Re = left.Re + right.Re; Im = left.Im + right.Im }

In FSI, we can add two complex numbers as follows:

> 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;}

Defining New Operators edit

In addition to overloading existing operators, its possible to define new operators. The names of custom operators can only be one or more of the following characters:

!%&*+-./<=>?@^|~

F# supports two types of operators: infix operators and prefix operators.

Infix operators edit

An infix operator takes two arguments, with the operator appearing in between both arguments (i.e. arg1 {op} arg2). We can define our own infix operators using the syntax:

let (op) arg1 arg2 = ...

In addition to mathematical operators, F# has a variety of infix operators defined as part of its library, for example:

let inline (|>) x f = f x
let inline (::) hd tl = Cons(hd, tl)
let inline (:=) (x : 'a ref) value = x.contents <- value

Let's say we're writing an application which performs a lot of regex matching and replacing. We can match text using Perl-style operators by defining our own operators as follows:

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()

This program outputs the following:

cat =~ dog: false
cat =~ cat|dog: true
monkey =~ monk*: true

Prefix Operators edit

Prefix operators take a single argument which appears to the right side of the operator ({op}argument). You've already seen how the ! operator is defined for ref cells:

type 'a ref = { mutable contents : 'a }
let (!) (x : 'a ref) = x.contents

Let's say we're writing a number crunching application, and we wanted to define some operators that work on lists of numbers. We might define some prefix operators in fsi as follows:

> 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
Previous: Exception Handling Index Next: Classes