Operator Overloading

F Sharp Programming · Wikibooks

0%

Contents

    Text

    Size
    100%
    Theme
    Typeface
    Line length
    Spacing

    From Wikibooks, under CC BY-SA 4.0, as the source states it. This page at Wikibooks.

    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

    You've already used operators:

    let sum = x + y
    

    Here + is example of using a mathematical addition operator.

    Operator Overloading

    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

    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

    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

    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