Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / F#

F# 5 : Operators

4.67/5 (2 votes)
4 Mar 2014CPOL5 min read 17.3K  
Operators in F#

Now I had intended to write a 1/2 decent blog post on F# operators, but then I had a think about this, and to be honest, I could not actually see too much merit in simply reiterating what was already freely available on MSDN where it lists ALL of the F# operators.

You can find a full list of all the F# operators and symbols on this MSDN page.

If you follow this link, the first thing you will realize is that F# has a lot of operators and symbols, far too many for me to include in a single blog post. With that in mind, I have taken my intention of creating a 1/2 decent blog post of operators, and decided to cut back the scope a bit to only include a discussion of the most common operators, so I guess you could say this blog will only be a 1/4 or 1/8 of a decent post, for which I humbly apologize.

Now before we start, I just wanted to say that I am only going to go through the most common operators, you will more than likely have to examine the MSDN link I included at the top of this post, when you really start to use F#, but for now I hope the ones I have chosen to concentrate on will be ok to get us started.

Oh one last thing, I am going to be pretty honest about this, so here goes, the brief description for each of the operators has been lifted directly from MSDN, it's one of those cases, when you are just meh “could not have said it better myself”, so didn’t and just borrowed um stole the stuff from MSDN.

Arithmetic Operators

The following table summarizes the binary arithmetic operators

+ Addition

Unchecked. Possible overflow condition when numbers are added together and the sum exceeds the maximum absolute value supported by the type.

- Subtraction

Unchecked. Possible underflow condition when unsigned types are subtracted, or when floating-point values are too small to be represented by the type.

* Multiplication

Unchecked. Possible overflow condition when numbers are multiplied and the product exceeds the maximum absolute value supported by the type.

/ Division

Division by zero causes a DivideByZeroException for integral types. For floating-point types, division by zero gives you the special floating-point values +Infinity or -Infinity. There is also a possible underflow condition when a floating-point number is too small to be represented by the type.

% Modulus

Returns the remainder of a division operation. The sign of the result is the same as the sign of the first operand.

** Exponentiation

Possible overflow condition when the result exceeds the maximum absolute value for the type. The exponentiation operator works only with floating-point types.

Demo

Here is a small demo of the Arithmetic operators listed above:

F#
//Arithmetic operators
printfn "25 + 25 = %i" (25 + 25)
printfn "75 - 25 = %i" (75 - 25)
printfn "12 * 12 = %i" (12 * 12)
printfn "100 / 4 = %i" (100 / 4)
printfn "101 %% 10 = %i" (101 % 10)
printfn "2 ** 3 = %f" (2.0 ** 3.0)

And here is the result of running this:

image

Binary Operators

The following table shows the binary comparison operators that are available for integral and floating-point types. These operators return values of type bool.

= Equals

This is not an assignment operator. It is used only for comparison. This is a generic operator.

> greater than

This is a generic operator.

< less than

This is a generic operator.

>= greater than or equal to

This is a generic operator.

<= greater than or equal to

This is a generic operator.

<> Not Equals

This is a generic operator.

Here is a small demo of the Binary operators listed above:

F#
//Binary operators
printfn "25 = 25 = %b" (25 = 25)
printfn "26 > 25 = %b" (26 > 25)
printfn "26 < 25 = %b" (26 < 25)
printfn "26 >= 25 = %b" (26 >= 25)
printfn "26 <= 25 = %b" (26 <= 25)
printfn "'a' <= 'b' = %b" ('a' <> 'b')
//how about a more complex example, a tuple
printfn "(1,'a') = (2,'a') = %b" ((1,'a') = (2,'a'))
printfn "(1,'a') = (1,'a') = %b" ((1,'a') = (1,'a'))
printfn "Some(1) = Some(2) = %b" (Some(1) = Some(2))
printfn "Some(2) = Some(2) = %b" (Some(2) = Some(2))

And here is the result of running this:

image

Boolean Operators

The following table summarizes the Boolean operators that are available in the F# language. The only type supported by these operators is the bool type.

not

Boolean negation

|| or

Boolean OR

&& and

Boolean AND

Here is a small demo of the Boolean operators listed above:

F#
//Boolean operators
printfn "not true = %b" (not true)
printfn "true || false = %b" (true || false)
printfn "true && true = %b" (true && true)
printfn "true && false = %b" (true && false)

And here is the result of running this:

image

Bitwise Operators

The following table describes the bitwise operators that are supported for unboxed integral types in the F# language.

&&& and

Bitwise AND operator. Bits in the result have the value 1 if and only if the corresponding bits in both source operands are 1.

||| or

Bitwise OR operator. Bits in the result have the value 1 if either of the corresponding bits in the source operands are 1.

^^^ XOR

Bitwise exclusive OR operator. Bits in the result have the value 1 if and only if bits in the source operands have unequal values.

~~~ negation

Bitwise negation operator. This is a unary operator and produces a result in which all 0 bits in the source operand are converted to 1 bits and all 1 bits are converted to 0 bits.

<<< bit shift left

Bitwise left-shift operator. The result is the first operand with bits shifted left by the number of bits in the second operand. Bits shifted off the most significant position are not rotated into the least significant position. The least significant bits are padded with zeros. The type of the second argument is int32.

>>> bit shift right

Bitwise right-shift operator. The result is the first operand with bits shifted right by the number of bits in the second operand. Bits shifted off the least significant position are not rotated into the most significant position. For unsigned types, the most significant bits are padded with zeros. For signed types, the most significant bits are padded with ones. The type of the second argument is int32.

Here is a small demo of the Bit shift operators listed above:

F#
//Bit shift operators

//&&& and
printfn "2 &&& 4 (which is 0010 &&& 0100, should be 0) = %X" (2 &&& 4)
printfn "2 &&& 3 (which is 0010 &&& 0011, should be 2) = %X" (2 &&& 3)
 
//||| or
printfn "2 ||| 4 (which is 0010 ||| 0100, should be 6) = %X" (2 ||| 4)
printfn "2 ||| 3 (which is 0010 ||| 0011, should be 3) = %X" (2 ||| 3)
   

//^^^ xor
printfn "2 ^^^ 4 (which is 0010 ^^^ 0100, should be 6) = %X" (2 ^^^ 4)
printfn "2 ^^^ 3 (which is 0010 ^^^ 0011, should be 1) = %X" (2 ^^^ 3)

//^^^ negate
printfn "~~~4 (which is not 0100, should be 1011 (B hex), or 11 decimal) = %X" (~~~4)

//<<< bit shift left
printfn "4 <<< 1 (which is 0100 <<< by 1 place left , should be 1000 (8 hex), or 8 decimal) = %X" (4 <<<  1)

//>>> bit shift right
printfn "4 >>> 1 (which is 0100 >>> by 1 place right , should be 0010 (2 hex), or 2 decimal) = %X" (4 >>>  1)

And here is the result of running this:

image

Operator Overloading

As I have already mentioned, there will be times when you do need to implement your own operator logic. In other .NET languages, this would be achieved by supplying your own operator overloads. It should come as no surprise that you need to do the same thing in F#. I did not want to get onto classes and OO just yet, but it kind of fits the current discussion so let's see how you might implement your own operators in a custom F# type.

Again, I have stolen this from MSDN. The following code illustrates a vector class that has just two operators, one for unary minus and one for multiplication by a scalar. In the example, two overloads for scalar multiplication are needed because the operator must work regardless of the order in which the vector and scalar appear.

F#
type Vector(x: float, y : float) =
   member this.x = x
   member this.y = y
   static member (~-) (v : Vector) =
     Vector(-1.0 * v.x, -1.0 * v.y)
   static member (*) (v : Vector, a) =
     Vector(a * v.x, a * v.y)
   static member (*) (a, v: Vector) =
     Vector(a * v.x, a * v.y)
   override this.ToString() =
     this.x.ToString() + " " + this.y.ToString()

For more information, you can see MSDN.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)