Phillip Trelford's blog... evidently
when your only tool is an analogy, everything looks like a simile.

Units of measure auto-conversion

June 14, 2010 12:36 by phil

In a recent article I described some prototype F# code for defining runtime units of measure with similar functionality to F#’s compile time units of measure feature. The following code extends this prototype to provide auto-conversion when adding or multiplying unit values. Note that as unit conversion is done at runtime this implementation is also usable from C#. This allows for example the following calculations to succeed:

1km + 200m = 1200m

(1m/s) / 500milliseconds = 2m

To achieve this a new Measure type introduces Base Unit types and Measure multiples.

    Base Unit type examples 
  • length
  • mass
  • time
    Measure multiple examples 
  • Kilometres (1000)
  • Metres (1)
  • Millimetres (0.001)

Defining measure types:

let length = "length"
let time = "time"
let m = Measure("m", BaseUnit(length))
let km = Measure.Kilo(m)
let s = Measure("s", BaseUnit(time))
let milliseconds = Measure.Milli(s)

Measure type definition:

type MeasureType = 
    | BaseUnit of string
    | Multiple of Measure * ValueType
    with
    member this.BaseUnitName =
        let rec traverse = function
            | BaseUnit s -> s
            | Multiple(Measure(_,m),_) -> traverse m
        traverse this
and Measure = Measure of string * MeasureType with  
    member this.Name = match this with Measure(s,_) -> s
    member this.Type = match this with Measure(_,t) -> t   
    static member Kilo (m:Measure) = 
        Measure("k"+m.Name,Multiple(m,1000.0))  
    static member Milli (m:Measure) = 
        Measure("m"+m.Name,Multiple(m,0.001))
    static member ( * ) (v:ValueType,m:Measure) = UnitValue(v,Unit(m,1))

The add and multiply operations on a UnitValue now convert to the base unit if a dimensional unit mismatch exits (see Units conversion by factor-label):

and UnitValue = UnitValue of ValueType * UnitType with
    member this.Value = match this with UnitValue(v,_) -> v
    member this.Unit = match this with UnitValue(_,u) -> u
    override this.ToString() = sprintf "%O %O" this.Value this.Unit
    static member ToBaseUnit x =
        let rec toBaseUnit = function
            | UnitValue(v,(Unit(Measure(_,BaseUnit(_)),_))) as x -> 
                x
            | UnitValue(v,Unit(Measure(_,Multiple(quantity,coefficient)),p)) -> 
                toBaseUnit (UnitValue(v*coefficient, Unit(quantity,p)))            
            | UnitValue(v,(CompositeUnit(xs))) ->
                let v, ys =
                    (v,[]) |> List.foldBack (fun x (v,ys) -> 
                        let x = toBaseUnit (UnitValue(v,x))
                        x.Value, x.Unit::ys
                    ) xs
                UnitValue(v, CompositeUnit(ys)) 
        toBaseUnit x
    static member private DoesDimensionalUnitMismatchExist lhs rhs =
        let rec measures = function
            | Unit(m,_) -> Set.singleton (m)
            | CompositeUnit(us) ->
                us |> List.map measures |> Set.unionMany                          
        measures lhs |> Set.exists (fun x ->
            measures rhs |> Set.exists (fun y ->
                y.Type.BaseUnitName = x.Type.BaseUnitName 
                && not (x = y)  
            )
        )
    static member (+) (lhs:UnitValue,rhs:UnitValue) =                         
        if lhs.Unit = rhs.Unit then       
            UnitValue(lhs.Value+rhs.Value, lhs.Unit+rhs.Unit)             
        else             
            let x1 = UnitValue.ToBaseUnit lhs
            let x2 = UnitValue.ToBaseUnit rhs
            if x1.Unit = x2.Unit then
                UnitValue(x1.Value+x2.Value,x1.Unit+x2.Unit)
            else                                                      
                raise (new System.InvalidOperationException())                 
    static member (*) (lhs:UnitValue,rhs:UnitValue) =            
        if UnitValue.DoesDimensionalUnitMismatchExist lhs.Unit rhs.Unit then            
            let lhs = UnitValue.ToBaseUnit lhs
            let rhs = UnitValue.ToBaseUnit rhs
            UnitValue(lhs.Value*rhs.Value,lhs.Unit*rhs.Unit)
        else
            UnitValue(lhs.Value*rhs.Value,lhs.Unit*rhs.Unit)   
    static member (*) (lhs:UnitValue,rhs:ValueType) =                        
        UnitValue(lhs.Value*rhs,lhs.Unit)      
    static member (/) (lhs:UnitValue,rhs:UnitValue) =
        if UnitValue.DoesDimensionalUnitMismatchExist lhs.Unit rhs.Unit then            
            let lhs = UnitValue.ToBaseUnit lhs
            let rhs = UnitValue.ToBaseUnit rhs
            UnitValue(lhs.Value/rhs.Value,lhs.Unit/rhs.Unit)
        else                 
            UnitValue(lhs.Value/rhs.Value,lhs.Unit/rhs.Unit)   
    static member (/) (lhs:UnitValue,rhs:ValueType) =
        UnitValue(lhs.Value/rhs,lhs.Unit) 

The only change to the Unit type is that it references a Measure type instead of a literal string signifying the measure:

and UnitType =
    | Unit of Measure * int
    | CompositeUnit of UnitType list
    static member Create(m) = Unit(m,1)
    override this.ToString() =
        let exponent = function
            | Unit(_,n) -> n
            | CompositeUnit(_) ->                
                raise (new System.InvalidOperationException())
        let rec toString = function        
            | Unit(s,n) when n=0 -> ""
            | Unit(Measure(s,_),n) when n=1 -> s
            | Unit(Measure(s,_),n)          -> s + " ^ " + n.ToString()            
            | CompositeUnit(us) ->               
                let ps, ns = 
                    us |> List.partition (fun u -> exponent u >= 0)
                let join xs = 
                    let s = xs |> List.map toString |> List.toArray             
                    System.String.Join(" ",s)
                match ps,ns with 
                | ps, [] -> join ps
                | ps, ns ->
                    let ns = ns |> List.map UnitType.Reciprocal
                    join ps + " / " + join ns
        match this with
        | Unit(_,n) when n < 0 -> " / " + toString this
        | _ -> toString this        
    static member ( * ) (v:ValueType,u:UnitType) = UnitValue(v,u)    
    static member ( * ) (lhs:UnitType,rhs:UnitType) =
        let text = function
            | Unit(Measure(s,_),_) -> s
            | CompositeUnit(us) -> us.ToString()       
        let normalize us u =
            let t = text u
            match us |> List.tryFind (fun x -> text x = t), u with
            | Some(Unit(s,n) as v), Unit(_,n') ->
                us |> List.map (fun x -> if x = v then Unit(s,n+n') else x)                 
            | Some(_), _ -> raise (new System.NotImplementedException())
            | None, _ -> us@[u]
        let normalize' us us' =
            us' |> List.fold (fun (acc) x -> normalize acc x) us        
        match lhs,rhs with
        | Unit(u1,p1), Unit(u2,p2) when u1 = u2 ->
            Unit(u1,p1+p2)
        | Unit(u1,p1), Unit(u2,p2) ->            
            CompositeUnit([lhs;rhs])
        | CompositeUnit(us), Unit(_,_) ->
            CompositeUnit(normalize us rhs)
        | Unit(_,_), CompositeUnit(us) ->
            CompositeUnit(normalize' [lhs]  us)
        | CompositeUnit(us), CompositeUnit(us') ->
            CompositeUnit(normalize' us us')
        | _,_ -> raise (new System.NotImplementedException())
    static member Reciprocal x =
        let rec reciprocal = function
            | Unit(s,n) -> Unit(s,-n)
            | CompositeUnit(us) -> CompositeUnit(us |> List.map reciprocal)
        reciprocal x
    static member ( / ) (lhs:UnitType,rhs:UnitType) =        
        lhs * (UnitType.Reciprocal rhs)
    static member ( + ) (lhs:UnitType,rhs:UnitType) =       
        if lhs = rhs then lhs                
        else raise (new System.InvalidOperationException())
and ValueType = float

    Known issues
  • Operator precedence means 10 * m / 2 * s = 5 m s instead of 5 m /s
    - As a workaround use brackets, i.e. (10 * m) / (2 * s)
  • Conversions requiring constant difference like degrees to kelvins are not supported

UnitType.fs (7.17 kb)


Tags:
Categories: .Net | C# | F#
Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed

Silverlight 4 Calculator Sample in F#

June 7, 2010 14:07 by Phil

If you have Silverlight 4 installed you should see a calculator sample below coded in F#. The sample originally targeted WPF, only a few modifications were required to run in Silverlight:

  • the view is hosted in a UserControl instead of a Window
  • a C# project is used to launch the UserControl and generate the Silverlight XAP file

The sample demonstrates creating a View in WPF or Silverlight without XAML. The idea is to make things a little easier from F# by implementing a (+) operator overload to attach dependency properties.

The following snippet shows the keypad being constructed by transforming tuples describing the key character and action to buttons:

let keys =
    let grid = new Grid()
    for i = 1 to 4 do
        ColumnDefinition() |> grid.ColumnDefinitions.Add 
        RowDefinition() |> grid.RowDefinitions.Add
    [ 
    ['7',Digit(7);'8',Digit(8);'9',Digit(9);'/',Operator(Divide)]
    ['4',Digit(4);'5',Digit(5);'6',Digit(6);'*',Operator(Multiply)]
    ['1',Digit(1);'2',Digit(2);'3',Digit(3);'-',Operator(Minus)]
    ['0',Digit(0);'.',Dot;'=',Evaluate;'+',Operator(Plus)]
    ]    
    |> List.mapi (fun y ys ->
        ys |> List.mapi (fun x (c,key) ->
            let color =
                match key with
                | Operator(_) | Evaluate -> Colors.Yellow
                | Digit(_) | Dot -> Colors.LightGray                        
            let effect =
                Binding("Operator",
                        Converter=operationEffectConverter,
                        ConverterParameter=key)    
            Button(Content=c,CommandParameter=key,
                Width=40.0,Height=40.0,Margin=Thickness(4.0),
                Background=SolidColorBrush(color)) +                
                Button.CommandBinding(Binding("KeyCommand")) +
                Button.EffectBinding(effect) +
                Grid.Column(x) + Grid.Row(y)                         
        )
    )
    |> List.concat
    |> List.iter (grid.Children.Add >> ignore)
    grid

 

Note: This article is more a thought experiment in trying F# code instead of XAML to describe a View. In many cases XAML with a C#/F# View Model may be the pragmatic choice.

PS There is a very concise WebSharper F# Calculator sample, that generates JavaScript.

SilverlightCalculator.zip (10.09 kb)


Tags:
Categories: .Net | Architecture | F# | Silverlight
Actions: E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed

Runtime Units of Measure for F#

May 29, 2010 15:13 by phil

The F# compiler includes a Units of Measure feature which infers a measure type at compile time, which means you get measure type safety with uncompromised runtime performance.

Example of F#’s built-in Units of Measure feature (hover over shows inferred type):

metres per second

Sometimes you might also want to actually infer units of measure at runtime, say to display the inferred unit type at the UI. The following F# code prototype provides such inference.

Lets start by defining some metres and seconds unit types:

let m = UnitType.Create("m")
let s = UnitType.Create("s")

Now with the source below we can explore types in F# Interactive:

> 10.0 * m;;
val it : UnitValue = 10 m {Unit = Unit ("m",1);
                           Value = 10.0;}
> 10.0 * m / 5.0 * s;;
val it : UnitValue = 2 m s {Unit = CompositeUnit [Unit("m",1); Unit("s",1)];
                            Value = 2.0;}

Source code to F# runtime units of measure:

type UnitType =
    | Unit of string * int 
    | CompositeUnit of UnitType list     
    static member Create(s) = Unit(s,1)
    override this.ToString() =
        let exponent = function
            | Unit(_,n) -> n
            | CompositeUnit(_) ->                
                raise (new System.InvalidOperationException())
        let rec toString = function        
            | Unit(s,n) when n=0 -> ""
            | Unit(s,n) when n=1 -> s
            | Unit(s,n)          -> s + " ^ " + n.ToString()            
            | CompositeUnit(us) ->               
                let ps, ns = 
                    us |> List.partition (fun u -> exponent u >= 0)
                let join xs = 
                    let s = xs |> List.map toString |> List.toArray             
                    System.String.Join(" ",s)
                match ps,ns with 
                | ps, [] -> join ps
                | ps, ns ->
                    let ns = ns |> List.map UnitType.Reciprocal
                    join ps + " / " + join ns
        match this with
        | Unit(_,n) when n < 0 -> " / " + toString this
        | _ -> toString this    
    static member ( * ) (v:ValueType,u:UnitType) = UnitValue(v,u)    
    static member ( * ) (lhs:UnitType,rhs:UnitType) =
        let text = function
            | Unit(s,n) -> s
            | CompositeUnit(us) -> us.ToString()
        let normalize us u =
            let t = text u
            match us |> List.tryFind (fun x -> text x = t), u with
            | Some(Unit(s,n) as v), Unit(_,n') ->
                us |> List.map (fun x -> if x = v then Unit(s,n+n') else x)                 
            | Some(_), _ -> raise (new System.NotImplementedException())
            | None, _ -> us@[u]
        let normalize' us us' =
            us' |> List.fold (fun (acc) x -> normalize acc x) us
        match lhs,rhs with
        | Unit(u1,p1), Unit(u2,p2) when u1 = u2 ->
            Unit(u1,p1+p2)        
        | Unit(u1,p1), Unit(u2,p2) ->            
            CompositeUnit([lhs;rhs])
        | CompositeUnit(us), Unit(_,_) ->
            CompositeUnit(normalize us rhs)
        | Unit(_,_), CompositeUnit(us) ->
            CompositeUnit(normalize' [lhs]  us)
        | CompositeUnit(us), CompositeUnit(us') ->
            CompositeUnit(normalize' us us')
        | _,_ -> raise (new System.NotImplementedException())
    static member Reciprocal x =
        let rec reciprocal = function
            | Unit(s,n) -> Unit(s,-n)
            | CompositeUnit(us) -> CompositeUnit(us |> List.map reciprocal)
        reciprocal x
    static member ( / ) (lhs:UnitType,rhs:UnitType) =        
        lhs * (UnitType.Reciprocal rhs)
    static member ( + ) (lhs:UnitType,rhs:UnitType) =       
        if lhs = rhs then lhs                
        else raise (new System.InvalidOperationException())
and ValueType = float
and UnitValue(v:ValueType,u:UnitType) = 
    member this.Value = v 
    member this.Unit = u
    override this.ToString() = sprintf "%O %O" v u
    static member (+) (lhs:UnitValue,rhs:UnitValue) =
        UnitValue(lhs.Value+rhs.Value, lhs.Unit+rhs.Unit)         
    static member (*) (lhs:UnitValue,rhs:UnitValue) =                    
        UnitValue(lhs.Value*rhs.Value,lhs.Unit*rhs.Unit)                
    static member (*) (lhs:UnitValue,rhs:ValueType) =        
        UnitValue(lhs.Value*rhs,lhs.Unit)      
    static member (*) (v:UnitValue,u:UnitType) = 
        UnitValue(v.Value,v.Unit*u)  
    static member (/) (lhs:UnitValue,rhs:UnitValue) =                    
        UnitValue(lhs.Value/rhs.Value,lhs.Unit/rhs.Unit)
    static member (/) (lhs:UnitValue,rhs:ValueType) =
        UnitValue(lhs.Value/rhs,lhs.Unit)  
    static member (/) (v:UnitValue,u:UnitType) = 
        UnitValue(v.Value,v.Unit/u)


Implementation details:

Unit (UnitType) computations are separate from value (UnitValue) computations. A single unit types (say metres) just has a name and a power (default of 1):

let metres = Unit(name = “metres”, power = 1)

To multiply by the same unit type, simply add the powers:

(2.0 * metres) * (3.0 metres) = 6.0 metres ^ 2

To handle composite unit types, when multiplying 2 unit values, first try to find a matching unit type in the existing list, if successful add the powers, otherwise add the new type:

2.0 * metres * seconds = 2 .0 metres (per) second

To divide simply multiply by the reciprocal:

(2.0 * metres * seconds) / (1.0 * seconds) = 2.0 metres per second * 1.0 seconds ^ -1

Resources:


Tags:
Categories: F# | .Net
Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed

Exposing F# Dynamic Lookup to C#, WPF & Silverlight

May 23, 2010 15:20 by phil

Like C#, F# is primarily a statically typed programming language. That said both languages provide support for dynamic typing.

Sometimes dynamic typing can be a pragmatic way of solving a specific problem. For example say you’re a solutions provider with a core product and have a number of clients with bespoke requirements. One client asks for a product rating feature. This can be relatively easily achieved using dynamic properties:

  • a bunch of client specific properties are read from the database, including the rating value, which is then set as a dynamic property on the product object
  • zero changes are required to the core code
  • at the UI, on WPF, the dynamic property can simply be bound through XAML like any other object property
  • on Silverlight 4,0 direct binding is not currently possible, however there is a simple workaround - specifying the dynamic property as a parameter for a value converter (example later)

C# and F# use slightly different approaches for dynamic properties:

  • C# 4.0 provides a dynamic type, which tells the compiler that member lookup on the object should be deferred to run time
  • F# employs a dynamic lookup operator, which when overloaded defines the behaviour at runtime. This means that in F# dynamic lookup is explicit (the ? operator), and can be mixed with static lookup on the same object (the . operator)

Is it is still possible to implement dynamic properties in F# that can be consumed by other .Net languages like C#, VB.Net, IronRuby or IronPython; plus WPF and Silverlight. The trick is to inherit from .Net 4.0’s System.Dynamic.DynamicObject type and implement the System.ComponentModel.INotifyPropertyChanged interface:

open System.Dynamic

/// Dynamic Lookup type
type DynamicLookup () =
    inherit DynamicObject ()
    /// Synchronization object
    let sync = obj()
    /// Property Changed event
    let propertyChanged = Event<_,_>()    
    /// Properties
    let mutable properties = Map.empty
    /// Gets property value
    member private this.GetValue name = 
        Map.tryFind name properties
    /// Sets property value, creating a new property if none exists
    member private this.SetValue (name,value) =
        /// Atomically writes new properties reference
        let Write () = 
            properties <-
                properties 
                |> Map.remove name 
                |> Map.add name value
        // Synchronize property writes
        lock sync Write
        // Trigger property changed event
        (this,System.ComponentModel.PropertyChangedEventArgs(name))
        |> propertyChanged.Trigger    
    override this.TryGetMember(binder:GetMemberBinder,result:obj byref ) =     
        match this.GetValue binder.Name with
        | Some value -> result <- value; true
        | None -> false
    override this.TrySetMember(binder:SetMemberBinder, value:obj) =        
        this.SetValue(binder.Name,value)
        true
    override this.GetDynamicMemberNames() =
        properties |> Seq.map (fun pair -> pair.Key)
    [<CLIEvent>]
    member this.PropertyChanged = propertyChanged.Publish
    interface System.ComponentModel.INotifyPropertyChanged with
        [<CLIEvent>]
        member this.PropertyChanged = propertyChanged.Publish     
    static member (?) (lookup:#DynamicLookup,name:string) =
        match lookup.GetValue name with
        | Some(value) -> value
        | None -> raise (new System.MemberAccessException())        
    static member (?<-) (lookup:#DynamicLookup,name:string,value:'v) =
        lookup.SetValue (name,value)
    static member GetValue (lookup:DynamicLookup,name) =
        lookup.GetValue(name).Value

F# usage:

/// Product type inherits dynamic lookup
type Product (name,price) =
    inherit DynamicLookup ()
    member this.Name = name
    member this.Price = price
 
// Initiate product object with dynamic rating value
let p = Product("F# for Scientists",49.95M)
do p?Stars <- 5
// Access product's properties
let stars = System.Convert.ToInt32(p?Stars)
do printf "%s...%M %s" p.Name p.Price (System.String('*',stars))

C# usage:

// Create Product type with dynamic stars value
Product product = new Product("Expert F#",54.99M);
((dynamic)product).Stars = 5;       
// Read product properties
dynamic p = product;
string s = 
    string.Format("{0}...{1} {2}",
        p.Name, p.Price, new String('*', (int) p.Stars));

Use from Silverlight 4.0

<t:PropertyLookup x:Key="DynamicConverter"/>

 

<TextBox Text="{Binding Converter={StaticResource DynamicConverter},
                ConverterParameter=Stars}"/>

 

dynamic product = new Product("Real World FP", 35.99);
product.Stars = 5;
DataContext = product;

 

public class PropertyLookup : IValueConverter
{
    public object Convert(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {        
        return DynamicLookup.GetValue(
            (DynamicLookup) value,
            (string) parameter);            
    }

    public object ConvertBack(object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Note: Silverlight 4.0 requires Microsoft.CSharp.dll to use dynamic types.


Tags:
Categories: F# | WPF | Silverlight | Architecture | .Net | C#
Actions: E-mail | Permalink | Comments (4) | Comment RSSRSS comment feed

F# operator overloads for WPF dependency properties

May 17, 2010 00:15 by Phil

When creating a desktop application with WPF using F# there are a number of options:

For small desktop applications, the last option, creating WPF elements directly from F# can produce good self-contained code, but at time is a little less readable than the XAML equivalent. Lets consider placing a button bound to a command on a grid at a certain position.

The XAML fragment might look like this:

<Button Content="_1" Command="{Binding Key1Command}"
        Grid.Column="0" Grid.Row="2"/>

 

Code equivalent:

let button = Button(Content="_1")
button.SetBinding(Button.CommandProperty,Binding("Key1Command")) |> ignore
Grid.SetColumn(button,0)
Grid.SetRow(button,2)

 

Code equivalent using (+) operator overloads to add the dependency properties:

Button(Content="_1") + Button.Command(Binding "Key1Command") 
    + Grid.Column 0 + Grid.Row 2 

 

The glue is just a couple of classes that define a dependency property and value/binding pair with a (+) operator overload that sets the value on the target WPF element.

For Dependency Property values:

type DependencyPropertyValuePair(dp:DependencyProperty,value:obj) =
    member this.Property = dp
    member this.Value = value
    static member (+) 
        (target:#UIElement,pair:DependencyPropertyValuePair) =
        target.SetValue(pair.Property,pair.Value)
        target

 

For Dependency Property bindings:

type DependencyPropertyBindingPair(dp:DependencyProperty,binding:BindingBase) =
    member this.Property = dp
    member this.Binding = binding
    static member (+) 
        (target:#FrameworkElement,pair:DependencyPropertyBindingPair) =
        target.SetBinding(pair.Property,pair.Binding) |> ignore
        target

 

Finally relevant WPF types must be extended with helper methods (note: this could be code generated):

type Grid with
    static member Column (value:int) =
        DependencyPropertyValuePair(Grid.ColumnProperty,value)
    static member Row (value:int) =
        DependencyPropertyValuePair(Grid.RowProperty,value)

 

Attached is a sample calculator VS2010 project showing the mechanism in action.

Calculator

Calculator.zip (3.57 kb)


Tags:
Categories: F# | WPF
Actions: E-mail | Permalink | Comments (4) | Comment RSSRSS comment feed