Home

Introduction

 

Fundamentals

 

Introduction

 

 

     
 
 

 

   
   
 

Home Copyright © 2015 FunctionX Home

Home

F# Collections: Sequences

 

Fundamentals of Sequences

 

Introduction to Series

Imagine you want to count (positive) numbers in increment of 2 starting at 0. You would get 0, 2, 4, 6, 8, 10, 12, and so on. Imagine you want to get negative numbers in decrement of 7 starting at -1. You would get -1, -8, -15, -22, -29, and so on. In mathematics, we refer to such lists as series. In both of our cases, we have:

In mathematics, the best or only way to represent a series is by using an expression. For our example, the series would represent all x natural numbers starting at 0 such that x = 2x.

Introduction to Sequences

A sequence is a series of values where the items follow a logic. Because the members of a sequence follow a specific and known logic, they must be:

Because you may not (or may never) get to the end of the series, a sequence is usually used where a fixed number of items from a series will be considered.

Creating a Sequence

 

Introduction

In F#, a sequence is created using the seq keyword followed by curly brackets. The formula to follow is:

seq { body }

The body of the sequence defines its series of values. You have many options.

A Sequence as a Range of Values

You can create a sequence as a range of values. Inside the curly brackets, use the formula:

StartValue .. EndValue

Here is an example:

seq { 0 .. 100 }

This would create the series as 0, 1, 2,  3, and so on.

Creating a Sequence from a Skip Range

You can also create a squence from a skip range. To do this, inside the curly brackets, use the formula:

Start .. Step .. End

Here is an example:

seq { 0 .. 3 .. 100 }

This would create the series as 0, 3, 6, 9, and so on.

Creating a Sequence from a Loop

You can create a sequence using a for loop/expression that indicates the expression that the values of the series would follow. The basic formula is:

for VariableName in Range -> body

The VariableName can be any lowercase letter or any name. The Range is usually specified in as Start Value .. End Value. The body of the loop is created after the -> sign. It can consist of and expression that uses the VariableName. Here is an example:

seq { for number in 0 .. 100 -> 2 * number + 1 }

An alternative to the -> operator is to use the do yield expression. Here is an example:

seq { for number in 0 .. 100 do yield 2 * number + 1 }

Naming a Sequence

To be able to refer to a sequence many times in your program, you should store it in a variable. This is done by let binding it to a variable. Here are examples:

let numbers       = seq { 0 .. 100 };
let interestRates = seq { 8.25 .. 0.25 .. 16.75 };
let evens         = seq { for nbr in 0 .. 50 -> 2 * nbr };

Accessing a Sequence

 

Accessing the Whole Sequence

To display the values of a sequence in the printf() or the sprintf() function, use %A in the placeholder. Here are examples:

open System
open System.Drawing
open System.Windows.Forms 

let exercise : Form = new Form(Text = "Sequences", ClientSize = new Size(160, 100))

let lblNumbers : Label = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblNumbers
lblNumbers.Text <- sprintf "Numbers %A" (seq { 0 .. 100 })

let lblValues : Label = new Label(Location = new Point(12, 42), AutoSize = true)
exercise.Controls.Add lblValues
lblValues.Text <- sprintf "Numbers %A" (seq { 0 .. 3 .. 100 })

let lblOdds : Label = new Label(Location = new Point(12, 72), AutoSize = true)
exercise.Controls.Add lblOdds
lblOdds.Text <- sprintf "Numbers %A" (seq {for number in 0 .. 100 -> 2 * number + 1 })

do Application.Run exercise

These would produce:

Accessing the Whole Sequence

If the sequence is stored in a variable, use its name to access it. Here are examples:

open System
open System.Drawing
open System.Windows.Forms 

let exercise : Form = new Form(Text = "Sequences", ClientSize = new Size(240, 100))

let lblNumbers : Label = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblNumbers

let lblInterestRates : Label = new Label(Location = new Point(12, 42),AutoSize=true)
exercise.Controls.Add lblInterestRates

let lblEvens : Label = new Label(Location = new Point(12, 72), AutoSize = true)
exercise.Controls.Add lblEvens

let numbers       = seq { 0 .. 100 }
let interestRates = seq { 8.25 .. 0.25 .. 16.75 }
let evens         = seq { for nbr in 0 .. 50 -> 2 * nbr }

lblNumbers.Text <- sprintf "Simple Numbers: %A" numbers
lblInterestRates.Text <- sprintf "Interest Rates: %A" interestRates
lblEvens.Text <- sprintf "Even Numbers: %A" evens

do Application.Run exercise

This would produce:

Accessing the Whole Sequence

Looping a Sequence

To access each value of a sequence, you can use a for loop whose variable would represent each individual item. Since all members are of the same type, you can use the appropriate character in the placeholder of the sprintf() function. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let exercise : Form = new Form(Text = "Numbers", ClientSize = new Size(140, 160))

let lbxNumbers = new ListBox(Location = new Point(28, 12), Size = new Size(80, 140))
exercise.Controls.Add lbxNumbers

let numbers = seq { 1 .. 10 }

for i in numbers do
    lbxNumbers.Items.Add(sprintf "Number: %d" i) |> ignore

do Application.Run exercise

This would produce:

Looping a Sequence

Of course, you can include any conditional statement(s) in the loop section. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let exercise : Form = new Form(Text = "Numbers", ClientSize = new Size(140, 100))

let lbxNumbers = new ListBox(Location = new Point(28, 12), Size = new Size(80, 80))
exercise.Controls.Add lbxNumbers

let numbers = seq { 1 .. 10 }

for i in numbers do
    if i % 2 <> 0 then
        lbxNumbers.Items.Add(sprintf "Number: %d" i) |> ignore

do Application.Run exercise

This would produce:

Looping a Sequence

Sequences and Functions

   

Creating and Returning a Sequence

You can have a function that returns a sequence. The simplest way is to have a function that creates a sequence and returns it. The function can return a regular list of values or a sequence created using a for loop that includes an expression. For example, in linear geometry, we learn that, to plot a line, we use an equation as:

y = ax + b

To use such a function, we can first choose a function such as 2x - y = -1 that can be converted to -y = -2x - 1 and then to y = 2x + 1. Then, to calculate the value of y, we can pass the value of x to a function as follows:

let getYGraphValue y = (2 * x) + 1

We can use such an expression in a sequence and let the function return a (partial) sequence of values. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues() = seq { for i in -2 .. 2 -> (2 * i) + 1 }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(170, 40))

let lblGraphValues = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblGraphValues

let line = generateGraphValues()

lblGraphValues.Text <- sprintf "Values: %A" line

do Application.Run exercise

This would produce:

Creating and Returning a Sequence

You can also have a function that takes arguments of any type and return a sequence. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = seq { for i in -2 .. 2 -> (a * i) + b }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(170, 40))

let lblGraphValues = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblGraphValues

let line = generateGraphValues -2 8 // 2x + y = 8 => y = -2x + 8

lblGraphValues.Text <- sprintf "Values: %A" line

do Application.Run exercise

This would produce:

Creating and Returning a Sequence

Passing a Sequence as Argument

A function can receive a sequence as parameter and use it in its body. At a minimum, the function can simply display the values of the sequence. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = seq { for i in -2 .. 2 -> (a * i) + b }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(140, 100))

let lbxGraphValues = new ListBox(Location = new Point(28, 12), Size = new Size(80, 80))
exercise.Controls.Add lbxGraphValues

let line = generateGraphValues -2 8 // 2x + y = 8 => y = -2x + 8

let showValues values =
    for v in values do
        lbxGraphValues.Items.Add(sprintf "Value: %i" v) |> ignore

showValues line

do Application.Run exercise

This would produce:

Passing a Sequence as Argument

Sequences and Tuples

 

A Sequence of Tuples

A sequence of tuples is a sequence where each element is a tuple, which can be a pair, a triple, or else. Such a sequence is in the form:

seq { (...); (...); ... }

To create the sequence, you can generate the values for each tuple using an expression through a for loop of a sequence. Make sure you provide the appropriate items for each tuple. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

let exercise : Form = new Form(Text = "Sequences", ClientSize = new Size(250, 40))

let lblGraphValues = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblGraphValues

let points = generateGraphValues 2 6

lblGraphValues.Text <- sprintf "Values: %A" points

do Application.Run exercise

This would produce:

A Sequence of Tuples

Notice that the result includes only the first four elements of the sequence. If you want to show all possible tuples from the sequence, you can access each one of them using a for loop. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 180))

let lblMessage = new Label(Location = new Point(12, 12), AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new Point(32,38), Size=new Size(120,130))
exercise.Controls.Add lbxGraphValues

let points = generateGraphValues 2 6

for pt in points do
    lbxGraphValues.Items.Add(sprintf "\t%A" pt) |> ignore

do Application.Run exercise

This would produce:

A Sequence of Tuples

Remember that you can pass a sequence to a function. You can then use the sequence in the body of the function however you want. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 180))

let lblMessage = new Label(Location = new Point(12, 12), AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new Point(32,38), Size=new Size(120,130))
exercise.Controls.Add lbxGraphValues

let points = generateGraphValues 2 6

let showPoints sequence =
    let mutable c : int = 65
    
    for pt in sequence do
        lbxGraphValues.Items.Add(sprintf "\t%c%A" (char c) pt) |> ignore
        c <- c + 1

showPoints points

do Application.Run exercise

This would produce:

A Sequence of Tuples

You can use a tuple that holds some values and extract a sequence from those values. In the same way, you can use two or more tuples and generate a sequence from them. Consider an equation of a line:

ax + by = c

Imagine you are given two points P and Q by which the line passes. Each point has coordinates for the horizontal axis x and for the vertical axis y. We can denote them as a and b. We can then consider the points as:

P(a1, b1)
Q(a2, b2)

To calculate the slope of the line, we can use the formula:

     b2 - b1
m = ---------
     a2 - a1

Once we have the slope, we can deduce the equation of the line as:

 y - b1 = m(x - a1)

Which is the same as:

y - b1 = mx - ma1

We can then perform the necessary substitions to calculate y:

ax + by = c	=> a1, a2, b1, b2 => P(a1, b1), Q(a2, b2)

     b2 - b1
m = ---------
     a2 - a1

y - b1 = m(x - a1)
y - b1 = mx - ma1

-mx + y = -ma1 + b1
 
    b2 - b1              b2 - b1
-x(---------) + y = -a1(---------) + b1
    a2 - a1              a2 - a1
 
 -b2x - b1x         -a1b2 + a1b1
------------ + y = -------------- + b1
   a2 - a1              a2 - a1
 

 b1x - b2x         a1b1 - a1b2
----------- + y = ------------- + b1
  a2 - a1            a2 - a1
 

 (b1 - b2)x         a1b1 - a1b2
----------- + y = ------------- + b1
  a2 - a1            a2 - a1


 (b1 - b2)x     (a2 - a1)y      a1b1 - a1b2    (a2 - a1)b1
----------- + ------------ = ------------- + --------------
  a2 - a1       a2 - a1         a2 - a1        a2 - a1

(b1 - b2)x + (a2 - a1)y = a1b1 - a1b2 + (a2 - a1)b1

(b1 - b2)x + (a2 - a1)y = a1b1 - a1b2 + a2b1 - a1b1

(b1 - b2)x + (a2 - a1)y = a1b1 - a1b1 - a1b2 + a2b1

(b1 - b2)x + (a2 - a1)y = a2b1 - a1b2

(b1 - b2)x + (a2 - a1)y = a2b1 - a1b2

(a2 - a1)y = a2b1 - a1b2 - (b1 - b2)x

     a2b1 - a1b2 - (b1 - b2)x
y = --------------------------
           (a2 - a1)

     a2b1 - a1b2 - b1x + b2x
y = --------------------------
           (a2 - a1)

Based on this, you can provide two tuples that hold two point coordinates by which a line passes, and then generate a sequence of points by which the line passes. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generatePoints (a1, b1) (a2, b2) =
    // (a1, b1) = Possible first point from which the line passes
    // (a2, b2) = Possible second point from which the line passes
    
    // With an equation as
    // y = ((a2 * b1) - (a1 * b2) - (b1 * x) + (b2 * x)) / (a2 - a1)
    // we can generate a sequence of pairs from 0 to 5
    seq { for n = 0 to 5 do yield (n, ((a2 * b1) - (a1 * b2) - (b1 * n) + (b2 * n)) / (a2 - a1)) }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(200, 75))

let lblMessage = new Label(Location = new Point(12, 12), AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lblPoints = new Label(Location = new Point(12, 42), AutoSize = true)
exercise.Controls.Add lblPoints

let points = generatePoints (1, 6) (3, 2)

lblPoints.Text <- sprintf "%A" points

do Application.Run exercise

This would produce:

A Sequence of Tuples

Notice that the result includes only the first four members. If you want to show all resulting tuples, you can access each member of the sequence using a for loop. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generatePoints (a1, b1) (a2, b2) =
    // (a1, b1) = Possible first point from which the line passes
    // (a2, b2) = Possible second point from which the line passes
    
    // With an equation as
    // y = ((a2 * b1) - (a1 * b2) - (b1 * x) + (b2 * x)) / (a2 - a1)
    // we can generate a sequence of pairs from 0 to 5
    seq { for n = 0 to 5 do yield (n, ((a2 * b1) - (a1 * b2) - (b1 * n) + (b2 * n)) / (a2 - a1)) }

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 135))

let lblMessage = new Label(Location = new Point(12, 12), AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new Point(32,38), Size=new Size(120,90))
exercise.Controls.Add lbxGraphValues

let points = generatePoints (1, 6) (3, 2)

for pt in points do
    lbxGraphValues.Items.Add(sprintf "%A" pt) |> ignore

do Application.Run exercise

This would produce:

A Sequence of Tuples

Since we used a function in this case, you can pass (a) tupple(s) and other (types of) parameters any way you want. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generatePoints (a1, b1) (a2, b2) start finish =
    // (a1, b1) = Possible first point from which the line passes
    // (a2, b2) = Possible second point from which the line passes
    
    // With an equation as
    // y = ((a2 * b1) - (a1 * b2) - (b1 * x) + (b2 * x)) / (a2 - a1)
    // we can generate a sequence of pairs from 0 to 5
    seq { for n = start to finish do yield (n, ((a2 * b1) - (a1 * b2) - (b1 * n) + (b2 * n)) / (a2 - a1)) }
    
let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 135))

let lblMessage = new Label(Location = new Point(12, 12), AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new Point(32,38), Size=new Size(120,90))
exercise.Controls.Add lbxGraphValues

let points = generatePoints (-2, 3) (3, 8) -2 3

for pt in points do
    lbxGraphValues.Items.Add(sprintf "\t%A" pt) |> ignore

do Application.Run exercise

This would produce:

A Sequence of Tuples

A Tuple of Sequences

The members of a tuple can be a sequence each. You can use existing (or already created) sequences and add them in the parentheses of a tuple. Here is an example:

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

let line1 = generateGraphValues 2 6
let line2 = generateGraphValues -3 -2
(line1, line2)

Or you can create the sequence directly in the parentheses of the tuple. Here is an example:

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

(generateGraphValues 2 6, generateGraphValues -3 -2)

Either way, once the tuple exists, you can use it. Here is an example:

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

sprintf "Points: %A" (generateGraphValues 2 6, generateGraphValues -3 -2)

If you want to use the tuple many times, you should store it in a variable. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }
    
let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(255, 55))

let lblMessage = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblMessage

let lines = generateGraphValues 2 6, generateGraphValues -3 -2
lblMessage.Text <- sprintf "Points: %A" lines

do Application.Run exercise

This would produce:

A Tuple of Sequences

If you want to individually identify the members of the tuple, you can create a name for each and use that name when necessary. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let generateGraphValues a b = // y = ax + b
    seq { for i in -4.00 .. 4.00 -> (i, (a * i) + b) }
                                 
let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(325, 105))

let lblNumbers1 = new Label(Location = new Point(12, 12), AutoSize = true)
exercise.Controls.Add lblNumbers1

let lblNumbers2 = new Label(Location = new Point(12, 42), AutoSize = true)
exercise.Controls.Add lblNumbers2

let lblNumbers3 = new Label(Location = new Point(12, 72), AutoSize = true)
exercise.Controls.Add lblNumbers3

let (line1, line2, line3) = (generateGraphValues 2.00 6.00,
                             generateGraphValues -3.00 -2.00,
                             generateGraphValues 0.50 2.00)

lblNumbers1.Text <- sprintf "Points: %A" line1
lblNumbers2.Text <- sprintf "Points: %A" line2
lblNumbers3.Text <- sprintf "Points: %A" line3

do Application.Run exercise

This would produce:

A Tuple of Sequences

Sequences and Classes/Structures

 

A Sequence of Objects

The members of a sequence can be objects from a structure or a class. Of course, you must first decide what type to use. You can use one of the classes or structures from the .NET Framework or you can create your own . You can then use it to generate the values of the sequence. For example, you can use a value, such as one from a primitive type, in a for loop of a sequence, build an object from there, and make it a member of a sequence. Here is an example:

Returning a Sequence of Objects from a Function

Just line a function can returns a sequence of primitive values, it can return a sequence of objects. Here is an example:

type Point(x : int, y : int) =
    let mutable ptX = x;
    let mutable ptY = y;
    member me.X with get() : int = ptX and set(value : int) = ptX <- value;
    member me.Y with get() : int = ptY and set(value : int) = ptY <- value;

let generateGraphPoints a b = // y = ax + b
    seq { for i in -4 .. 4 -> new Point(i, (a * i) + b) }

You must provide a way to access each member of the sequence. One way you can do this is to create a method that can expose the object. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

type Point(x : int, y : int) =
    let mutable ptX = x;
    let mutable ptY = y;
    member me.X with get() : int = ptX and set(value : int) = ptX <- x;
    member me.Y with get() : int = ptY and set(value : int) = ptY <- y;
    member me.Expression() = "P(" + (string ptX) + ", " + (string ptY) + ")"

let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 180))

let lblMessage = new Label(Location = new System.Drawing.Point(12, 12),
			   AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new System.Drawing.Point(24, 38),
				 Size = new System.Drawing.Size(140, 130))
exercise.Controls.Add lbxGraphValues

let generateGraphPoints a b = // y = ax + b
    seq { for i in -4 .. 4 -> new Point(i, (a * i) + b) }

let points = generateGraphPoints -3 -2

for pt in points do
    lbxGraphValues.Items.Add(sprintf "\t%A" (pt.Expression())) |> ignore

do Application.Run exercise

This would produce:

A Sequence of Objects

In the above example, we passed two integers to a function and used them to pass two arguments to the constructor of a class. In the same way, you can pass one or more objects to a function that would use it/them to create a sequence of objects. Here is an example where a function receives two points created each from a class. The function uses the members of that object to create a tuple. A series of the resulting tuples is used as members of a sequence:

open System
open System.Drawing
open System.Windows.Forms 

type Point(x : int, y : int) =
    let mutable ptX = x
    let mutable ptY = y
    member me.X with get() : int = ptX and set(value : int) = ptX <- x
    member me.Y with get() : int = ptY and set(value : int) = ptY <- y

let generatePoints (P : Point) (Q : Point) =
    // P = One of the points by which the line passes
    // Q = Another point by which the line passes
    seq { for n = 0 to 5 do yield (n, ((Q.X * P.Y) - (P.X * Q.Y) - (P.X * n) + (Q.Y * n)) / (Q.X - P.X)) }
 
let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 140))

let lblMessage = new Label(Location = new System.Drawing.Point(12, 12),
                           AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new System.Drawing.Point(24, 38),
                                 Size = new System.Drawing.Size(140, 90))
exercise.Controls.Add lbxGraphValues

let points = generatePoints (Point(-2, 3)) (Point(3, 8))

for pt in points do
    lbxGraphValues.Items.Add(sprintf "\t%A" pt) |> ignore

do Application.Run exercise

This would produce:

A Sequence of Objects

A Sequence as a Member of a Class

A member of a class or structure can be a sequence. This means that a property can be a sequence. When creating the property, you can use the getter to specify how the property will get its sequencial values. Here is an example of a class with two sequence-based properties:

type SystemOfEquations (line1 : Line, line2 : Line) =
    let mutable l1 = line1;
    let mutable l2 = line2;
    member this.Line1 with get() : Line = l1 and set(value : Line) = l1 <- value;
    member this.Line2 with get() : Line = l2 and set(value : Line) = l2 <- value;
    member this.Points1 with get() = seq { for i in -2.00 .. 2.00 -> (l1.Point1.X * i) + l1.Point1.Y }
    member this.Points2 with get() = seq { for i in -2.00 .. 2.00 -> (l2.Point1.X * i) + l2.Point1.Y }

You can then access the property outside the class just as you would any other property. Here is an example:

type Point(x : float, y : float) =
    let mutable ptX = x;
    let mutable ptY = y;
    member me.X with get() : float = ptX and set(value : float) = ptX <- value;
    member me.Y with get() : float = ptY and set(value : float) = ptY <- value;
    member me.Expression() = "P(" + (string ptX) + ", " + (string ptY) + ")"

type Line(pt1 : Point, pt2 : Point) =
    let mutable ptX = pt1;
    let mutable ptY = pt2;
    member self.Point1 with get() : Point = ptX and set(value : Point) = ptX <- value;
    member self.Point2 with get() : Point = ptY and set(value : Point) = ptY <- value;
    // member self.Length ...

type SystemOfEquations (line1 : Line, line2 : Line) =
    let mutable l1 = line1;
    let mutable l2 = line2;
    member this.Line1 with get() : Line = l1 and set(value : Line) = l1 <- value;
    member this.Line2 with get() : Line = l2 and set(value : Line) = l2 <- value;
    member this.Points1 with get() = seq { for i in -2.00 .. 2.00 -> (l1.Point1.X * i) + l1.Point1.Y }
    member this.Points2 with get() = seq { for i in -2.00 .. 2.00 -> (l2.Point1.X * i) + l2.Point1.Y }
    member this.Relationship() : string =
        let m1 : float = (l1.Point1.Y - l1.Point2.Y) / (l1.Point2.X - l1.Point1.X)
        let m2 : float = (l2.Point1.Y - l2.Point2.Y) / (l2.Point2.X - l2.Point1.X)
        if m1 = m2 then
            "Lines are parallel"
        elif (((l1.Point1.Y - l1.Point2.Y) / (l1.Point2.X - l1.Point1.X)) * ((l2.Point1.Y - l2.Point2.Y) / (l2.Point2.X - l2.Point1.X))) = -1.000000 then
            "Lines are perpendicular"
        else
            "Lines are neither parallel nor perpendicular"

let soe1 = SystemOfEquations(Line(Point(-1.00, -2.00), Point( 1.00,  2.00)), Line(Point(-2.00,  0.00), Point( 0.00,  4.00)))
let soe2 = SystemOfEquations(Line(Point( 0.00, -4.00), Point(-1.00, -7.00)), Line(Point( 3.00,  0.00), Point(-3.00,  2.00)))
let soe3 = SystemOfEquations(Line(Point(-4.00,  2.00), Point( 0.00,  3.00)), Line(Point(-3.00, -2.00), Point( 3.00,  2.00)))

Characteristics of, and Operations on, Sequences

 

Introduction

To support sequences, the F# language is equipped with a namespace named Microsoft.FSharp.Collections. This namespace contains a module named Seq (also used as a class).

Creating a Sequence

You create a sequence by specifying the logic by which the values will be added to it. If you are not ready to provide for the sequence, you can create it as empty. To support this, the Seq is equipped with a method named empty. Here is an example of using it:

let points = Seq.empty

If the variable is mutable, you can add values to it. Here is an example:

let generateGraphValues a b = // y = ax + b
    seq { for i in -4 .. 4 -> (i, (a * i) + b) }

let mutable points = Seq.empty

points <- generateGraphValues 2 6

Combining Sequences

If you have two or more sequences, you can combine them to get a new one as a result of such a combination. The formula to follow is:

seq {
    yield! sequence1
    . . .
    yield! sequence_n}

The formula uses seq {}. Inside the curly brackets, specify each sub-sequence starting it with yield!. If a sub-sequence is created locally, of course its values or its creation must be included in its own curly brackets. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let exercise : Form = new Form(Text = "Numbers", ClientSize = new Size(140, 160))

let lbxNumbers = new ListBox(Location = new Point(28, 12), Size = new Size(80, 140))
exercise.Controls.Add lbxNumbers

let numbers = seq {
    yield! { 1 .. 5 }
    yield! { 8 .. 12 } }

for i in numbers do
    lbxNumbers.Items.Add(sprintf "Number: %d" i) |> ignore

do Application.Run exercise

This would produce:

Combining Sequences

Of course, one or all the internal sequences can come from previous created sequences. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let exercise : Form = new Form(Text = "Numbers", ClientSize = new Size(140, 160))

let lbxNumbers = new ListBox(Location = new Point(28, 12), Size = new Size(80, 140))
exercise.Controls.Add lbxNumbers

let evens = seq { 0 .. 2 .. 9 }
let odds  = seq { 1 .. 2 .. 10 }

let numbers = seq {
    yield! evens
    yield! odds }

for i in numbers do
    lbxNumbers.Items.Add(sprintf "Number: %d" i) |> ignore

do Application.Run exercise

This would produce:

Combining Sequences

Iterating Through a Sequence

To let you apply a function to each item, the Seq class is equipped with a method named iter. Its signature is:

Seq.iter : ('T -> unit) -> seq<'T> -> unit

Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

type Point(x : int, y : int) =
    let mutable ptX = x;
    let mutable ptY = y;
    member me.X with get() : int = ptX and set(value : int) = ptX <- value;
    member me.Y with get() : int = ptY and set(value : int) = ptY <- value;
    member me.Expression() = "P(" + (string ptX) + ", " + (string ptY) + ")"

let generateGraphPoints a b = // y = ax + b
    seq { for i in -4 .. 4 -> new Point(i, (a * i) + b) }
 
let exercise : Form = new Form(Text = "Geometry", ClientSize = new Size(190, 180))

let lblMessage = new Label(Location = new System.Drawing.Point(12, 12),
                           AutoSize = true)
lblMessage.Text <- "Points by which the line passes:"
exercise.Controls.Add lblMessage

let lbxGraphValues = new ListBox(Location = new System.Drawing.Point(24, 38),
                                 Size = new System.Drawing.Size(140, 130))
exercise.Controls.Add lbxGraphValues

let points = generateGraphPoints -3 2

Seq.iter (fun (pt : Point) -> lbxGraphValues.Items.Add(sprintf "\t%s" (pt.Expression())) |> ignore) points

do Application.Run exercise

This would produce:

Iterating Through a Sequence

Finding Out Whether a Member Exists

To let you check whether an element exists in a sequence, the Seq class is equipped with a method named exists. Its signature is:

Seq.exists : ('T -> bool) -> seq<'T> -> bool

The first argument is a a Boolean function that will apply a conditional statement. The second argument is the sequence on which  the function will be applied to check the existence of the item. Here is an example:

type Point(x : int, y : int) =
    let mutable ptX = x;
    let mutable ptY = y;
    member me.X with get() : int = ptX and set(value : int) = ptX <- value;
    member me.Y with get() : int = ptY and set(value : int) = ptY <- value;
    member me.Expression() = "P(" + (string ptX) + ", " + (string ptY) + ")"

let generateGraphPoints a b = // y = ax + b
    seq { for i in -4 .. 4 -> new Point(i, (a * i) + b) }

let points = generateGraphPoints 2 6;

let passesByOrigin = Seq.exists (fun (pt : Point) -> (pt.X = 0) && (pt.Y = 0)) points

Home Copyright © 2014-2015, FunctionX Home