Using interfaces

Category:
Defining Types and Functions
Description: A longer sample showing how to use interfaces to model 'data' objects such as abstract points. Somewhat contrived, since multiple repreentations of points are unlikely practice, but for larger computational objects maintaining flexibility of representation through using interfaces or function values is often crucial.
Code:
type IPoint = 
abstract X : float
abstract Y : float


/// Implementing an interface with an object expression.
let Point(x,y) =
{ new IPoint with
member obj.X=x
member obj.Y=y }

/// Implementing an interface with an object expression that has mutable state
let MutablePoint(x,y) =
let currX = ref x
let currY = ref y
{ new IPoint with
member obj.X= currX.Value
member obj.Y= currY.Value }

/// This interface is really just a function since it only has one
/// member, but we give it a name here as an example. It represents
/// a function from some variable to (X,Y)
type ILine =
abstract Get : float -> IPoint

/// Implementing an interface with an object expression.
///
/// Here a line is specified by gradient/intercept
let Line(a:float,c:float) =
let y(x) = a * x + c
{ new ILine with
member l.Get(x) = Point(x, y(x)) }

/// Implementing an interface with a class.
///
/// Here a line is specified by gradient/intercept
type GradientInterceptLine(a:float,c:float) =
// Some local bindings
let y(x) = a * x + c

// Publish additional properties of the object
member x.Gradient = a
member x.Intercept = c

// Also implement the interface
interface ILine with
member l.Get(x) = Point (x,y(x))

let InterfaceSample3() =

// This creates an object using a function
let line1 = Line(1.0, 0.344)

// This creates a similar object using a type.
let line2 = new GradientInterceptLine(2.0,1.5) :> ILine
let origin = { new IPoint with
member p.X =0.0
member p.Y = 0.0 }
let point1 = line1.Get(-1.0)
let point2 = line2.Get(0.0)
let point3 = line2.Get(1.0)
let outputPoint os (p:IPoint) = fprintf os "(%f,%f)" p.X p.Y
printfn "origin = %a" outputPoint origin;
printfn "point1 = %a" outputPoint point1;
printfn "point2 = %a" outputPoint point2;
printfn "point3 = %a" outputPoint point3

Execution Result:
origin = (0.000000,0.000000)
point1 = (-1.000000,-0.656000)
point2 = (0.000000,1.500000)
point3 = (1.000000,3.500000)

Upcast and downcast

Category:
Defining Types and Functions
Description: Use upcast and downcast
Code:
let UpcastDownCastSample1() = 
let a = 1
let upcastFunction(x) : obj = upcast x
let downcastFunction(x:obj) : int = downcast x
let objValue = upcastFunction(a)
printfn "name = %A" objValue
printfn "int = %d" (downcastFunction(objValue))

Execution Result:
name = 1
int = 1

Generic Type

Category:
Defining Types and Functions
Description: Define a generic type
Code:
type TrackedValue<'Kind>(v : 'Kind) =
let mutable value = v
let mutable reads = 0
let mutable writes = 0

member this.Value
with get() =
reads <- reads + 1
value
and set newVal =
writes <- writes + 1
value <- newVal

let GenericSample1() =
let a = TrackedValue(10)
let b = TrackedValue(20.0)
let c = TrackedValue<_>("Hello")
printfn "%d %f %s" a.Value b.Value c.Value

Execution Result:
10 20.000000 Hello

Function with type contraints

Category:
Defining Types and Functions
Description: Define function with type contraints
Code:
let inline parseFunction< ^T when ^T : (static member Parse: string -> ^T) > s =
(^T: (static member Parse: string -> ^T) s)

let TypeConstraintsSample1() =
let ``seq`` = [ "1"; "2"; "3" ] |> List.map parseFunction
``seq`` |> Seq.iter (printfn "%d")

Execution Result:
1
2
3

Function with type contraints

Category:
Defining Types and Functions
Description: Define function with type contraints
Code:
let inline tryParseFunction< ^T when ^T : (static member TryParse: string * ^T byref -> bool) > s =
let mutable x = Unchecked.defaultof< ^T>
if (^T: (static member TryParse: string * ^T byref -> bool) (s, &x))
then Some x
else None

let TypeConstraintsSample2() =
let ``seq`` = [ "1"; "2"; "3"; "NotInt" ] |> List.map tryParseFunction
``seq`` |> Seq.iter (printfn "%A")

Execution Result:
Some 1
Some 2
Some 3


Function with type contraints

Category:
Defining Types and Functions
Description: Define function with type contraints
Code:
let inline tryParseFunction2 s =
let mutable x = Unchecked.defaultof< ^T>
if (^T: (static member TryParse: string * ^T byref -> bool) (s, &x))
then Some x
else None

let TypeConstraintsSample3() =
let ``seq`` = [ "1"; "2"; "3"; "NotInt" ] |> List.map tryParseFunction2
``seq`` |> Seq.iter (printfn "%A")

Execution Result:
Some 1
Some 2
Some 3


Infinite sequence

Category:
Defining Types and Functions
Description: Infinite sequence
Code:
let InfiniteSeqSample1() = 
let evenNumbers:bigint seq =
let rec f n = seq { yield n; yield! f (n+2I) }
f 0I
printfn "infinite seq = %A" evenNumbers

Execution Result:
infinite seq = seq [0; 2; 4; 6; ...]

Last edited Sep 12, 2011 at 11:16 PM by ttliu2000, version 1

Comments

No comments yet.