суббота, 29 мая 2010 г.

F# Parsing simple language

During my professional career I often met the task of code generation based on some source data. Last time it was analogue of BCL compiler for ExpressionTrees and then C# compiler have done mostly all the required job with parsing expressions. It is time to invert our responsibilities and feel ourselves in the shoes of compiler. As a test animal we’ll take MiniML-like language (without binary/unary operators and with slightly modified syntax).

Parsing

Out first goal is transformation of plain character stream into the structured representation. First of all we’ll declare components of abstract syntax tree (AST)

namespace MiniML

type Ast =
| Let of string * Ast * Ast
| Letrec of string * Ast * Ast
| Var of string
| Integer of int
| Lambda of string * Ast
| Apply of Ast * Ast
| IfThenElse of Ast * Ast * Ast

With tools like fslexx/fsyacc creation of parser becomes a easy task, however today we’ll use another techique named parser combinators and define parser using F# itself. More details about this approach can be found in the documents below:

Disclaimer:Version of parser given in sample is pretty straightforward and ineffective for the sake of clearness

First of all we need to declare basic elements and combinators to create more complex parsers.

namespace MiniML

module BaseParsing =
open System

// result of parsing - either value+remaining part of char stream or evidence of failure
type ParseResult<'T> = Success of 'T * list<char> | Failed
// parser itself - function from list of chars to parsing result
type Parser<'T> = Parser of (list<char> -> ParseResult<'T>)

let apply (Parser p) s = p s
let run p l = apply p (Seq.toList l)

// wraps given value into parser keeping char stream untouched
let one v = Parser( fun cs -> Success(v, cs) )
let failed () = Parser (fun _ -> Failed)

// binds subsequent parsers
let bind p f = Parser (fun cs ->
match apply p cs with
| Success(r, cs2) -> apply (f r) cs2
| Failed -> Failed
)
// (OR combinator) applies first parser, if it fails - applies second
let (<|>) p1 p2 = Parser(fun cs ->
match apply p1 cs with
| Failed -> apply p2 cs
| ok -> ok
)
// (AND combinator) applies first parser to source stream, then applies second to remaining part of stream
let (<&>) p1 p2 = Parser(fun cs ->
match apply p1 cs with
| Success(_, cs2) -> apply p2 cs2
| Failed -> Failed
)
// applies given predicate to first symbol in the stream, on success transforms the symbol with p function
let choose f p = Parser(fun cs ->
match cs with
| c::cs2 when f c -> Success(p c, cs2)
| _ -> Failed
)
// selects digit and returns it as a result
let digit = choose Char.IsDigit id
// selects digit and returns unit
let digitU = choose Char.IsDigit ignore
// selects letter and returns it as a result
let letter = choose Char.IsLetter id
// selects digit and returns unit
let letterU = choose Char.IsLetter ignore
// selects letter or digit and returns it as a result
let letterOrDigit = choose Char.IsLetterOrDigit id
// selects digit and returns unit
let letterOrDigitU = choose Char.IsLetterOrDigit ignore
// selects given char and returns it as a result
let char c = choose ((=) c) id
// selects given char and returns unit
let charU c = choose ((=) c) ignore
// selects whitespace
let ws = choose Char.IsWhiteSpace ignore

// To enable computation expresion syntax
type ParserBuilder() =
member this.Return(v) = one v
member this.Bind(p, f) = bind p f
member this.ReturnFrom(p) = p
member this.Zero() = failed ()
let parser = ParserBuilder()

// applies given parser zero or more times. results are composed with v0 using f (in fold like manner)
let rec zeroOrMany p f v0 = parser {
return! oneOrMany p f v0 <|> one v0
}
// applies given parser one or more times. results are composed with v0 using f (in fold like manner)
and oneOrMany p f v0 = parser {
let! v1 = p
return! zeroOrMany p f (f v0 v1)
}

// repetition of given parser 0 or more times (similar to * in regexes)
let zeroOrManyU p = zeroOrMany p (fun _ _ -> ()) ()
// repetition of given parser 1 or more times (similar to + in regexes)
let oneOrManyU p = oneOrMany p (fun _ _ -> ()) ()
// transforms parser result with f function
let map p f = parser {
let! v = p
return f v
}

Now we can declare language grammar itself

namespace MiniML

module MiniMLParser =

open System
open BaseParsing

// Helpers

// checks if parsed text matches given string
let text (s : string) = Parser(fun cs ->
let rec loop l p =
if p >= s.Length then Success((), l)
else
match l with
| h::tl when h = s.[p] -> loop tl (p + 1)
| _ -> Failed
loop cs 0
)
// defines parser that consumes 0+ whitespaces + specified parser
let ws0Plus p = zeroOrManyU ws <&> p
// defines parser that consumes 1+ whitespaces + specified parser
let ws1Plus = oneOrManyU ws
// matches 0+ whitespaces + specifies string
let ws0Text s = ws0Plus (text s)
let ws1Text s = ws1Plus <&> (text s)
// matches 0+ whitespaces + specified char
let ws0Char c = ws0Plus (charU c)

// list of language keywords
let keywords = set ["let"; "letrec"; "in"; "if"; "then"; "else"]

// zero or more whitespaces + optional '-' + one or more digit
let integer = parser {
let! sign = ws0Plus ((char '-' <&> one -1) <|> (one 1))
let! value = 0 |> oneOrMany digit (fun acc v -> acc * 10 + (int v - int '0'))
return sign * value
}

// zero or more whitespaces + letter + zero or more letters or digits
// result should not be keyword
let identifier = parser {
let! f = ws0Plus letter
let sb = (new Text.StringBuilder()).Append(f)
let! r = sb |> zeroOrMany letterOrDigit (fun acc v -> acc.Append(v))
let text = r.ToString()
if not <| keywords.Contains(text)
then return text
}

let rec expr =
let parseIdentifier = map identifier Var
let parseNumber = map integer Integer

let parseLet, parseLetrec =
let p keyword f = parser {
do! ws0Text keyword <&> ws
let! id = identifier
do! ws0Char '='
let! value = expr
do! ws1Text "in"<&> ws
let! body = expr
return f(id, value, body)
}
p "let" Let, p "letrec" Letrec

let parseLambda = parser {
do! ws0Char '\\'
let! id = identifier
do! ws0Text "->"
let! body = expr
return Lambda(id, body)
}

let parseBracketed = parser {
do! ws0Char '('
let! e = expr
do! ws0Char ')'
return e
}

let parseApply = parser {
let! f = parseIdentifier <|> parseBracketed
return! f |> oneOrMany (parseIdentifier <|> parseNumber <|> parseBracketed) (fun acc e -> Apply(acc, e))
}

let parseIfThenElse = parser {
let body = parseIdentifier <|> parseBracketed <|> parseNumber

do! ws0Text "if" <&> ws
let! cond = parseIdentifier <|> parseBracketed
do! ws1Text "then" <&> ws
let! ifTrue = body
do! ws1Text "else" <&> ws
let! ifFalse = body
return IfThenElse(cond, ifTrue, ifFalse)

}

parseLet <|> parseLetrec <|> parseLambda <|> parseIfThenElse <|> parseApply <|> parseBracketed <|> parseIdentifier <|> parseNumber

let parse s = run expr s

To visualize parsing results we’ll use auxiliary function toString

open MiniML

let rec astToString = function
| Let(name, v, body) ->
sprintf "let %s =
%s in
%s" name (astToString v) (astToString body)
| Letrec(name, v, body) ->
sprintf "letrec %s =
%s in
%s" name (astToString v) (astToString body)
| Apply(arg, r) -> sprintf("(%s %s)") (astToString arg) (astToString r)
| IfThenElse(cond, ifTrue, ifFalse) ->
sprintf "if %s
then %s
else %s" (astToString cond) (astToString ifTrue) (astToString ifFalse)
| Integer(v) -> string v
| Lambda(name, body) -> sprintf "\%s -> %s" name (astToString body)
| Var(name) -> name

let parse s =
match MiniMLParser.parse s with
| BaseParsing.Success(r, []) -> printfn "%s" (astToString r)
| BaseParsing.Success(r, rest) ->
printfn "Warning: remaining chars found %A" rest
printfn "%s" (astToString r)
| BaseParsing.Failed -> printfn "Parsing failed for %s" s

let sources =
[
@"letrec length = \l -> if (null l) then 0 else (add 1 (length (tail l))) in length"
@"letrec fact = \x -> if (eq x 1) then 1 else (mul x (fact (add x -1))) in fact"
@"let f = \x -> \y -> (cons (x y) y) in f"
]

for src in sources do
parse src
(*
letrec length =
\l -> if (null l)
then 0
else ((add 1) (length (tail l))) in
length
letrec fact =
\x -> if ((eq x) 1)
then 1
else ((mul x) (fact ((add x) -1))) in
fact
let f =
\x -> \y -> ((cons (x y)) y) in
f
*)

All right, parsing step is completed but now we are facing another problem: our AST doesn’t contain any information about expression types (except the primitive numeric values). Luckily we know the answer.

Type inference

Wikipedia defines type inference as

Type inference, or implicit typing, refers to the ability to deduce automatically the type of a value in a programming language

In our compiler we’ll implement Hindley Milner type inference algorithm that is used by F# itself (as well as Haskell, Ocaml etc). Also nice and simple explanation can be found in ScalaByExample or here.

namespace MiniML

exception TypeInferenceException of Ast * string

module Types =
open System

type TypeVarName = string

// basic entity in the algorithm
type Type =
| TypeVar of TypeVarName
| Function of Type * Type
| TypeConstructor of string * Type list
override this.ToString() =
match this with
| TypeVar(name) -> name
| Function(arg, res) -> sprintf "(%O -> %O)" arg res
| TypeConstructor(name, args) ->
if List.isEmpty args
then name
else sprintf "%s[%s]" name (String.Join(", ", args |> Seq.map string))

exception UnificationException of Type * Type

// creates fresh type variables
type TypeVarGenerator() =
let n = ref 0
member this.New() =
incr n
TypeVar(sprintf "T%d" !n)

// represents mapping between types
[<AbstractClass>]
type Substitution private() =
static let empty = {new Substitution() with override this.Lookup(tv) = TypeVar(tv) }
static member Empty = empty

abstract Lookup : TypeVarName -> Type
member this.Run(t) =
match t with
| TypeVar tv ->
let substituted = this.Lookup(tv)
if t = substituted then substituted
else this.Run(substituted)
| Function(a, r) ->
Function(this.Run(a), this.Run(r))
| TypeConstructor(name, tyArgs) ->
TypeConstructor(name, tyArgs |> List.map this.Run)

member this.Extend(v : TypeVarName, t : Type) =
{ new Substitution() with override __.Lookup(tv) = if v = tv then t else this.Lookup(tv) }

// type + free type variables in type
// Instance returns new type where all free variables are replaces with fresh type vars
type TypeScheme(tyVars : Set<_>, t, gen : TypeVarGenerator) =
let subst = (Substitution.Empty, tyVars) ||> Seq.fold(fun s tt -> s.Extend(tt, gen.New() ))
let instance = subst.Run(t)
member this.Instance = instance
member this.TypeVariables = tyVars
member this.Type = t

// maps names to type schemes
// contains auxiliary functions that extracts type vars from different entities
module Env =
type Environment = Map<string, TypeScheme>

let rec typeVarsOfType = function
| TypeVar(tv) -> Set.singleton tv
| Function(a, r) -> typeVarsOfType(a) + typeVarsOfType(r)
| TypeConstructor(_, tyArgs) -> (Set.empty, tyArgs) ||> List.fold (fun acc ty -> acc + typeVarsOfType ty)

let typeVarsOfScheme(s : TypeScheme) =
(typeVarsOfType s.Type) - s.TypeVariables

let typeVarsOfEnv(e : Environment) =
let schemes = e |> Map.toSeq |> Seq.map snd
(Set.empty, schemes) ||> Seq.fold (fun acc s -> acc + (typeVarsOfScheme s))

let typeToScheme (env : Environment, t : Type, gen) =
TypeScheme((typeVarsOfType t) - (typeVarsOfEnv env), t, gen)

type Inferencer() =
let nameGenerator = TypeVarGenerator()

// calculates substitution that can convert two specified types into equivalent one
let rec unify(a : Type, b : Type, s : Substitution) =
match(s.Run(a), s.Run(b)) with
| TypeVar(ta), TypeVar(tb) when ta = tb ->
s
| TypeVar(ta), _ when not <| Env.typeVarsOfType(b).Contains(ta) ->
s.Extend(ta, b)
| _, TypeVar(_) ->
unify(b, a, s)
| Function(a1, b1), Function(a2, b2) ->
unify(a1, a2, unify(b1, b2, s))
| TypeConstructor(name1, args1), TypeConstructor(name2, args2) when name1 = name2 ->
(s, args1, args2) |||> List.fold2 (fun subst t1 t2 -> unify(t1, t2, subst))
| x,y -> UnificationException(x,y) |> raise

// predefines types and expressions
let newTypeVar = nameGenerator.New()
let newTypeScheme t = Env.typeToScheme(Map.empty, t, nameGenerator)

let boolean = TypeConstructor("bool", [])
let integer = TypeConstructor("int", [])
let list(t) = TypeConstructor("list", [t])

let builtins =
[
"true", newTypeScheme(boolean)
"false", newTypeScheme(boolean)
"nil", newTypeScheme(list(newTypeVar))
"cons", newTypeScheme(Function(newTypeVar, Function(list(newTypeVar), list(newTypeVar))))
"null", newTypeScheme(Function(list(newTypeVar), boolean))
"eq", newTypeScheme(Function(newTypeVar, Function(newTypeVar, boolean)))
"add", newTypeScheme(Function(integer, Function(integer, integer)))
"mul", newTypeScheme(Function(integer, Function(integer, integer)))
"sub", newTypeScheme(Function(integer, Function(integer, integer)))
"tail", newTypeScheme(Function(list(newTypeVar), list(newTypeVar)))
"head", newTypeScheme(Function(list(newTypeVar), newTypeVar))
] |> Map.ofList

// compute general substitution (based on s) for the pair of ast and baseType
let rec analyze (e : Env.Environment, ast, baseType : Type, s : Substitution) =
try
match ast with
| Integer(v) ->
unify(integer, baseType, s)
| Var(name) ->
if not (e.ContainsKey name)
then failwithf "Name %s no found" name

let schema = e.[name]
unify(schema.Instance, baseType, s)
| Lambda(arg, body) ->
let a = nameGenerator.New()
let b = nameGenerator.New()

let s1 = unify(baseType, Function(a, b), s)
let newEnv = e.Add(arg, TypeScheme(Set.empty, a, nameGenerator))
analyze(newEnv, body, b, s1)
| Apply(f, arg) ->
let a = nameGenerator.New()
let s1 = analyze(e, f, Function(a, baseType), s)
analyze(e, arg, a, s1)
| Let(name, inV, body) ->
let a = nameGenerator.New()
let s1 = analyze(e, inV, a, s)
analyze(e.Add(name, Env.typeToScheme(e, s1.Run(a), nameGenerator)),body, baseType, s1)
| Letrec(name, inV, body) ->
let t = nameGenerator.New()
let newEnv = e.Add(name, TypeScheme(Set.empty, t, nameGenerator))
let s1 = analyze(newEnv, inV, t, s)
analyze(e.Add(name, Env.typeToScheme(e, s1.Run(t), nameGenerator)), body, baseType, s1)

| IfThenElse(cond, ifTrue, ifFalse) ->
let s1 = analyze(e, cond, boolean, s)
let s2 = analyze(e, ifTrue, baseType, s1)
analyze(e, ifFalse, baseType, s2)
with
UnificationException(t1, t2) -> TypeInferenceException(ast, sprintf "Cannot unify %O and %O" t1 t2) |> raise

// renames type variables into good-looking ones
let alpha (t) =
let l = ref 'A'
let map = Collections.Generic.Dictionary<_, _>()
let rec run = function
| TypeVar(name) ->
if not <| map.ContainsKey(name) then
let newName = string (!l)
l := Convert.ToChar(int !l + 1)
map.Add(name, newName)
TypeVar(map.[name])
| Function(arg, res) -> Function(run arg, run res)
| TypeConstructor(name, typeArgs) -> TypeConstructor(name, List.map run typeArgs)
run t

member this.TypeOf(ast) =
let a = nameGenerator.New()
analyze(builtins, ast, a, Substitution.Empty).Run(a) |> alpha

Some samples

open MiniML

let sources =
[
@"if (1) then true else false", "incorrect condition type"
@"if true then 1 else false", "different types for conditional branches"
@"letrec fold =
\f -> \s -> \l -> if (null l) then s else (fold f (f s (head l)) (tail l)) in
fold", "generic fold"
@"letrec fold =
\f -> \s -> \l -> if (null l) then s else (fold f (f s (head l)) (tail l)) in
fold add", "partial application"
@"letrec length = \l -> if (null l) then 0 else (add 1 (length (tail l))) in length", "recursive definition1"
@"letrec fact = \x -> if (eq x 1) then 1 else (mul x (fact (add x -1))) in fact", "factorial"
@"let f = \x -> \y -> (cons (x y) y) in f", ""
]

let rec astToString = function
| Let(name, v, body) ->
sprintf "let %s =
%s in
%s" name (astToString v) (astToString body)
| Letrec(name, v, body) ->
sprintf "letrec %s =
%s in
%s" name (astToString v) (astToString body)
| Apply(arg, r) -> sprintf("(%s %s)") (astToString arg) (astToString r)
| IfThenElse(cond, ifTrue, ifFalse) ->
sprintf "if %s
then %s
else %s" (astToString cond) (astToString ifTrue) (astToString ifFalse)
| Integer(v) -> string v
| Lambda(name, body) -> sprintf "\%s -> %s" name (astToString body)
| Var(name) -> name

let parse (s, comment) =
printfn "===%s" comment
let inferencer = Types.Inferencer()
match MiniMLParser.parse s with
| BaseParsing.Success(r, []) ->
printfn "%s" (astToString r)
let text = try inferencer.TypeOf(r).ToString() with TypeInferenceException(ast, text) -> sprintf "%s: %s" (astToString ast) text
printfn "Type: %s" text
| _ -> printfn "Parsing failed for %s" s

for src in sources do
parse src
(*
===incorrect condition type
if 1
then true
else false
Type: 1: Cannot unify int and bool
===different types for conditional branches
if true
then 1
else false
Type: false: Cannot unify bool and int
===generic fold
letrec fold =
\f -> \s -> \l -> if (null l)
then s
else (((fold f) ((f s) (head l))) (tail l)) in
fold
Type: ((A -> (B -> A)) -> (A -> (list[B] -> A)))
===partial application
letrec fold =
\f -> \s -> \l -> if (null l)
then s
else (((fold f) ((f s) (head l))) (tail l)) in
(fold add)
Type: (int -> (list[int] -> int))
===recursive definition1
letrec length =
\l -> if (null l)
then 0
else ((add 1) (length (tail l))) in
length
Type: (list[A] -> int)
===factorial
letrec fact =
\x -> if ((eq x) 1)
then 1
else ((mul x) (fact ((add x) -1))) in
fact
Type: (int -> int)
===
let f =
\x -> \y -> ((cons (x y)) y) in
f
Type: ((list[A] -> A) -> (list[A] -> list[A]))
*)

Notes:

  1. Substutution is principal of the algorithm. It is function that maps type variables in given type to other types. Base substitution is Empty that is simple identity mapping. Inferencer.unify method creates general substitution that
    • Extend source substitution
    • Can convert two specified type into equivalent one
  2. TypeScheme describes structure of the type. It contains type itself and all type variables that is free in type (not captured from environment)
  3. Type inference mechanism relies on known information about built-in basic types (defined by builtins map)
  4. After type inference process is completed we perform alpha conversion for type variables to replace temporary names with nice looking ones

вторник, 18 мая 2010 г.

Copy-And-Update in C#

Disclaimer: only for demonstration purposes :).

Immutability is natural for F# types; tuples, lists and records are immutable by default. Also records have special syntax “copy-and-update” that allows creation copy of existing record specifying only modified fields.

type DataObject = 
{ Id : int
Value : string
Object : DataObject2 }
and DataObject2 =
{ Price : decimal
PriceType : string }

let o1 = {Id = 100; Value = "Value"; Object = {Price = 10m; PriceType = "CleanPrice"}}
let o2 = {o1 with Id=500; Object = {o1.Object with Price = 500m} }
(*
val o1 : DataObject = {Id = 100;
Value = "Value";
Object = {Price = 10M;
PriceType = "CleanPrice";};}
val o2 : DataObject = {Id = 500;
Value = "Value";
Object = {Price = 500M;
PriceType = "CleanPrice";};}
*)

C# doesn't provide similar things, but using VS 2010 and combination of named and optional parameters we can achive almost the same level of expressiveness.

var o1 = new DataObject(100, "Value1", new DataObject2(10m, "CleanPrice"));
var o2 = o1.With(id: 500, obj: o1.Object.With(price: 500));
Console.WriteLine(o1);
Console.WriteLine(o2);
//Id = 100, Value = Value1, Object = (Price:10, PriceType=CleanPrice)
//Id = 500, Value = Value1, Object = (Price:500, PriceType=CleanPrice)

Pretty close to original, huh? Idea of implementation is very simple, we somehow need to distinguish missing values from entered. To achieve it we introduce struct Optional that will hold all input parameters

    public struct Optional<T>
{
public T Value;
public bool HasValue;

public Optional(T value)
{
HasValue = true;
Value = value;
}

public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
public T ValueOrDefault(T defaultValue) { return HasValue ? Value : defaultValue; } }

With method in each class declare its arguments with type Optional<T> and default value default( Optional<T>). This is simple solution, all entered arguments shall be converted by implicit operator and thus have HasValue=true. Optional is struct because otherwise it is impossible to input null as user defined value, it shall be interpreted not as valid value but rather as missing one.

    public class DataObject
{
public int Id { get; private set; }
public string Value { get; private set; }
public DataObject2 Object { get; private set; }

public DataObject(int id, string value, DataObject2 o)
{
Id = id;
Value = value;
Object = o;
}

private DataObject()
{
}

public override string ToString()
{
return string.Format("Id = {0}, Value = {1}, Object = ({2})", Id, Value ?? "null", Object != null ? Object.ToString() : "null");
}

public DataObject With(
Optional<int> id = default(Optional<int>),
Optional<string> value = default(Optional<string>),
Optional<DataObject2> obj = default(Optional<DataObject2>)
)
{
return new DataObject
{
Id = id.ValueOrDefault(Id),
Value = value.ValueOrDefault(Value),
Object = obj.ValueOrDefault(Object)
};
}
}

public class DataObject2
{
public decimal Price { get; private set; }
public string PriceType { get; private set; }

public DataObject2(decimal price, string priceType)
{
Price = price;
PriceType = priceType;
}

private DataObject2()
{
}

public DataObject2 With(
Optional<decimal> price = default(Optional<decimal>),
Optional<string> priceType = default(Optional<string>)
)
{
return new DataObject2
{
Price = price.ValueOrDefault(Price),
PriceType = priceType.ValueOrDefault(PriceType)
};
}

public override string ToString()
{
return string.Format("Price:{0}, PriceType={1}", Price, PriceType ?? "null");
}
}

суббота, 15 мая 2010 г.

F#: Active Patterns

Introduction

Pattern matching is an extremely powerful feature supported by F#. Ability to decompose composite data structure into constituent parts (recursively by support of nested patterns) makes analysis of complex objects a piece of cake. As a sample we can take insertion operation for AVL tree and implement tree rotation with pattern matching. Entire process is nicely demonstrated on the picture below.

type Tree<'T> = 
| Nil
| Node of Tree<'T> * 'T * Tree<'T>

let rec height = function
| Nil -> 0
| Node(l, _, r) -> 1 + max (height l) (height r)

// balance factor - difference between heights
let balance l r = height l - height r

// extracts value contained in tree
let valueOf = function
| Nil -> failwith "Nil has no value"
| Node(_, v, _) -> v

///Tree is valid if both left and right subtree are valid and balance factor of tree is lesser than 2
let rec validate = function
| Nil -> true
| Node(l, _, r) ->
validate l && validate r && (abs (balance l r) < 2)

// Rotate functions
let rotateLL = function
| Node(Node(ll, lv, lr), v, r) -> Node(ll, lv, Node(lr, v, r))
| x -> failwithf "Unexpected %O" x
let rotateRR = function
| Node(l, v, Node(rl, rv, rr)) -> Node(Node(l, v, rl), rv, rr)
| x -> failwithf "Unexpected %O" x
let rotateLR = function
| Node(Node(ll, lv, Node(lrl, lrv, lrr)), v, r) -> Node(Node(ll, lv, lrl), lrv, Node(lrr, v, r))
| x -> failwithf "Unexpected %O" x
let rotateRL = function
| Node(l, v, Node(Node(rll, rlv, rlr), rv, rr)) -> Node(Node(l, v, rll), rlv, Node(rlr, rv, rr))
| x -> failwithf "Unexpected %O" x

// the hero of blogpost: multi-case active pattern
let (|Lesser|Greater|Equals|) (a, b) =
if a < b then Lesser
else if a = b then Equals
else Greater

let rec insert v = function
| Nil -> Node(Nil, v, Nil)
| Node(l, c, r) as self->
// common part
// if balance factor of newly inserted node and its sibling is equal to threshold value (2)
// we should rebalance tree
let doInsert inserted newNode sibling previous rotateL rotateR =
if balance inserted sibling = 2 then
if v < valueOf previous then rotateL newNode
else rotateR newNode
else newNode
match (v,c) with
| Equals -> self
| Lesser ->
let inserted = insert v l
let newNode = Node(inserted, c, r)
doInsert inserted newNode r l rotateLL rotateLR
| Greater ->
let inserted = insert v r
let newNode = Node(l, c, inserted)
doInsert inserted newNode l r rotateRL rotateRR

let flip f x y = f y x
let random = seq {
let rnd = new System.Random()
while true do
yield rnd.Next()
}
let tree = (Nil, Seq.take 1000 random) ||> Seq.fold (flip insert)

printfn "%O" (validate tree) // True

Code of rotation routines is almost verbatim translation of the picture. As you see description of each case takes three source lines, IMO very good result. Without pattern matching analysis of nested elements will be much more cumbersome.

F# spec defines large number of pattern forms that are already built in language. However sometimes it is not enough to express intentions of the developer, you may need to desconstuct the F# structure in application-dependent way (split list of numbers into two parts with odd in first and evens in second) or the object is opaque to F# (interoperabiliy issue). Luckily F# allows writing custom recognizers that can participate in pattern matching as first class citizens (as opposed to functions that can appear only in guards), this language feature is called Active Patterns.

Single Case Active Recognizer.

The first and the simpliest kind of Active Patterns is Single Case pattern – it just converts one value to another without putting restrictions on type of result.

open System.Drawing

let (|ARGB|) (c : Color) = c.A, c.R, c.G, c.B
let (ARGB (a, r, g, b)) = Color.Aquamarine
(*
val r : byte = 127uy
val g : byte = 255uy
val b : byte = 212uy
val a : byte = 255uy
*)

Single Case pattern can also be used with additional parameters. F# specification puts Parameterized Single Case Patterns into separate group but for the sake of simplicity (IMO) basic Single Case patterns can be imagined as parameterized ones with no arguments.

//Value to match comes as a last mandatory argument.
(|SingleCase|) [arg0…argn] input

This type of Active Patterns doesn’t perform filtering of incoming values; it is converter and nothing more. However you can always mix it with other patterns (i.e. constant pattern).

type Object(id : int) = 
member this.Id = id

let (|Id|) (o : Object) = o.Id

// initially active recognizer extracts value of Id from the object, then Id is matched with simple constant pattern
let selectObjectWithSpecificIds o =
match o with
| Id 10 -> printfn "Object with id=10 found"
| Id 20 -> printfn "Object with id=20 found"
| _ -> printfn "Required object not found"

selectObjectWithSpecificIds (Object(100))
(*
Required object not found
*)
selectObjectWithSpecificId (Object(10))
(*
Object with id=10 found
*)

Sometimes it is enough, but ofter you need to pick objects based on more complex criteria and in this case the guy you need – partial active recognizer.

Partial Active Recognizer.

This type of recognizers combines abilities of the Single Case patterns with a possibility to reject input value; that’s why they return not just ‘T but option<’T>.

// tests if specified string value can be parsed as int value
let (|Int|_|) v =
match Int32.TryParse(v) with
| (true, v) -> Some(v)
| false, _ -> None

let (Int x) = "100" // x = 100
match "a" with
| Int v -> printfn "this is int value %d" v
| _ -> printfn "something else"
(*
something else
*)

By the way of application this recognizer is close to function passed into List.choose, you can simultaneously perform filtering and conversion. In fact you can directly use recognizer as a function in choose

let lst = ["1"; "a"; "2"; "b"; "3"]
let res = lst |> List.choose (|Int|_|)
printfn "%O" res
(*
[1; 2; 3]
*)

Similarly to Single Case patterns Partial Active recognizers can accept parameters, everything that was previously said regarding Single Case patterns is also applicable to partial ones. Declaration syntax is slightly different

// last argument is mandatory
(|Partial|_|) [arg0…argn] input


// tests if specified string value can be parsed as int value
let (|Int|_|) v =
match Int32.TryParse(v) with
| (true, v) -> Some(v)
| false, _ -> None

// tests if specified string value can be parsed as double value
let (|Double|_|) v =
match Double.TryParse(v) with
| true, v -> Some(v)
| false, _ -> None

// tests if specified string value starts with given prefix
let (|Prefix|_|) prefix (s : string) =
if s.StartsWith(prefix) then Some(s.Substring(prefix.Length))
else None

let classifyString s =
match s with
| Int v -> printfn "Int: %d" v
| Double v -> printfn "Double: %f" v
| Prefix "http://" v -> printfn "String that starts with http://: %s" v

You can notice that if we try to compile code from above, the compiler will issue warning FS0025: Incomplete pattern matches on this expression. because it cannot verify that match cases are exhaustive. If you have fixed number of categories and want to put matched value into one of them  then you definitely should use third kind of active recognizers: multi case active recognizer.

Multi-Case Active Recognizer

This type of recognizers makes input value fall into one of existing categories. Recognizers of this kind differ from the ones we’ve already seen: first of all they do not accept any arguments except input value, second: they return Choice<…>.Declaration syntax is following:

// Сase1..СaseN is disguised Choice
(|Case1|Case2|..|CaseN|) input

We can rewrite slightly modified sample with multicase recognizers and make sure that warning dissapears.

// ( |Int|Double|Other| ) : string -> Choice<int,float,string>
let (|Int|Double|Other|) s =
match Int32.TryParse(s) with
| (true, v) -> Int(v)
| false, _ ->
match Double.TryParse(s) with
| true, v -> Double(v)
| false, _ -> Other(s)

let classifyString s =
match s with
| Int v -> printfn "Int: %d" v
| Double v -> printfn "Double: %f" v
| Other s -> printfn "Other string %s" s

Practical application

Everything is limited by the imagination :). Adam Granicz‘ve posted amazing article about creating parsers based on active patterns. Nice example is interoperability with another .Net languages, you can easily enhance existing object with pattern matching capabilities without converting them to F# friendly structures.

using System.Collections.Generic;
using System.Linq;

namespace CSharp
{
public class DataObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }

public static List<DataObject> Create(int n)
{
return Enumerable
.Range(1, n)
.Select(i => new DataObject {Id = i, Name = "Name:" + i, Value = "Value:" + i}).
ToList();
}
}
}
open CSharp
module CSInterop =
// single case patterns
let (|Id|) (o : DataObject) = o.Id
let (|Name|) (o : DataObject) = o.Name
let (|Value|) (o : DataObject) = o.Value

// partial patterns (why I cannot use ? in identifiers like I can in Schema)
// my dream
//let (|Id?|_|) id (o : DataObject) = if o.Id = id then Some(o) else None
let (|Id_|_|) id (o : DataObject) = if o.Id = id then Some(o) else None
let (|Name_|_|) name (o : DataObject) = if o.Name = name then Some(o) else None
let (|Value_|_|) value (o : DataObject) = if o.Value = value then Some(o) else None

open CSInterop

let namesValues = DataObject.Create(5) |> Seq.map(function | Name name & Value value -> name + " " + value)
let findObject n = DataObject.Create(5) |> Seq.tryPick(function | Id_ n _ & Name name -> Some(name) | _ -> None)

Ability to decompose structure in arbitrary way is extremly powerful. With Active Patterns can perform pattern matching over any object model created in any .NET language. Processing XML, traversing LINQ expression trees, various file system based operations, decomposing text with regular expressions and binding matched group to the list elements or tuple components…You are the master of the Universe!

As a close-to-life sample we’ll examine transformation of expression trees. Often it is useful to describe structure of the objects with simple and straightforward expressions and later mechanically transform them into more complex ones. Expression can be used both for deducing type of field for the UI components and as a source for creating accessor delegates.

public class DataObject
{
public int Id { get; set; }
public string Name { get; set; }
}

Expression<Func<DataObject, string[]>> Expr = obj => obj.Name.Split(',');

Expression Expr describes what actions need to be performed to obtain result and provides complete type-related information. Unfortunatly we cannot use this compiled version of this expression directly because it is error-prone: NullReferenceException will be thrown in case of null argument or null Name property. Sad, but not fatal: we can easily detect all possible null references in this expression and transform it so all dangerous calls will be routed through special function.

type Methods private() = 
static member ClassBindMethod = typeof<Methods>.GetMethod("ClassBind")
static member ClassBind<'T when 'T : null and 'T : equality>(t : 'T, f : Func<'T, obj>) =
if t <> null then f.Invoke(t)
else box null

Transformed version will look like this:

ClassBind(obj, p0 => ClassBind(p0.Name, p1 -> p1.Split(',')))

Disclaimer: implementation below is made just for demonstration and supports only reference types as possible null candidates.

open System
open System.Collections.Generic
open System.Linq.Expressions

type Methods private() =
static member ClassBindMethod = typeof<Methods>.GetMethod("ClassBind")
static member ClassBind<'T when 'T : null and 'T : equality>(t : 'T, f : Func<'T, obj>) =
if t <> null then f.Invoke(t)
else box null


let isNullable(t : Type) = t.IsClass || t.IsInterface

// Multi-Case pattern for expression
let (|MemberAccess|MethodCall|Lambda|Other|) (expr : Expression) =
match expr.NodeType with
| ExpressionType.Lambda ->
let lambda = expr :?> LambdaExpression
Lambda(lambda.Type, lambda.Parameters, lambda.ReturnType, lambda.Body)
| ExpressionType.MemberAccess ->
let memberAccess = expr :?> MemberExpression
MemberAccess(memberAccess.Expression, memberAccess.Member)
| ExpressionType.Call ->
let call = expr :?> MethodCallExpression
MethodCall(call.Object, call.Method, call.Arguments |> Seq.toList)
| _ -> Other(expr)

// gathers nullable candidates from given expression
// checks instance argument in member accesses and method calls
let rec collectNullableExpressions e =
match e with
| Lambda(_, _, _, body) -> collectNullableExpressions body
| MemberAccess(instance, _) when instance <> null ->
let l1 = collectNullableExpressions instance
if isNullable instance.Type then instance::l1 else l1
| MethodCall(instance, _, args) ->
let l1 =
if instance <> null
then if isNullable instance.Type then instance::(collectNullableExpressions instance) else collectNullableExpressions instance
else []
(List.collect collectNullableExpressions args) @ l1
| _ -> []

// replaces all nullable references in expressions to the corrected values
let rec fixNullableRefs (map : Dictionary<_, _>) e =
match e with
| MemberAccess(instance, memberInfo) when instance <> null && map.ContainsKey instance ->
Expression.MakeMemberAccess(snd map.[instance], memberInfo) :> Expression, true
| MethodCall(instance, methodInfo, args) when instance <> null && map.ContainsKey instance ->
Expression.Call(snd map.[instance], methodInfo, args |> List.map (fixNullableRefs map >> fst) |> List.toArray) :> Expression, true
| MethodCall(instance, methodInfo, args) ->
let (fixedArgs, changes) = List.map (fixNullableRefs map) args |> List.unzip
if (List.exists id changes) then
Expression.Call(instance, methodInfo, fixedArgs |> List.toArray) :> Expression, true
else
e, false
| x -> x, false

let fix<'T when 'T :> LambdaExpression> (e :'T) =
let nullables =
collectNullableExpressions e
|> List.rev
|> Seq.distinct
|> List.ofSeq
let counter = ref 0
let map = new Dictionary<_, _>()
for nullable in nullables do
let (patchedExpr, hasChanges) = fixNullableRefs map nullable
let param = Expression.Parameter(nullable.Type, sprintf "p%d" !counter)
map.[nullable] <- ((if hasChanges then patchedExpr else nullable), param)
incr counter
let fixedBody,_ = fixNullableRefs map e.Body
let newBody =
(nullables, fixedBody)
||> List.foldBack(fun n body ->
let (patchedExpr, param) = map.[n]
let bind = Methods.ClassBindMethod.MakeGenericMethod(n.Type)
let funcType = typedefof<Func<_,_>>.MakeGenericType(n.Type, typeof<obj>)
let lambda = Expression.Lambda(funcType, body, [|param|])
Expression.Call(bind, patchedExpr, lambda) :> Expression
)
Expression.Lambda(e.Type, Expression.Convert(newBody, e.Body.Type), e.Parameters) :?> 'T

let source = DataObject.Expr
let patched = fix source
printfn "%O" patched
(*
obj => Convert(ClassBind(obj, p0 => ClassBind(p0.Name, p1 => p1.Split(new [] {,}))))
*)

четверг, 29 апреля 2010 г.

Nature of value restriction

Introduction

Value restriction is an error that firstly makes a direct hit in the brain of non-prepared developer. It has no straight analogues in the majority of mainstream languages and thus very confusing. Fortunately error message produced by compiler contains comprehensive solution. However IMO good developer cannot use the tool without having a knowledge how it works under the hood. Otherwise programming becomes some sort of magic… This is not the way of Jedi.

Let’s start from the very beginning. In addition to other useful and interesting features F# supports parametric polymorphism. This means that we can define data types or functions that handle all arguments in the uniform way without depending on its actual type. For example:

// declare type parameters explicitly
let len<'T> (l : 'T list) = List.length l // 'T list -> int
// F# type inference mechanism infers most generic type
let len2 l = List.length l // 'T list -> int

let l1 = len [1;2;3]
let l2 = len ["1";"2";"3"]

let l3 = len2 [1;2;3]
let l4 = len2 ["1";"2";"3"]

Len and Len2 are polymorphic functions; they can operate on arbitrary lists.

In addition to polymorphic functions and data types F# allows to declare polymorphic values, the most well-known example is empty list.

let nil = [] // 'a list
let a = 1::nil // int list
let b = "1"::nil // string list

In the sample above nil acts as a value of int list and string list. Another piece of code, at that time with option:

let none = None // 'a option
let intRes = defaultArg none 1 // int
let stringRes = defaultArg none "1" // string

Everything is cool and safe, but note – we’ve used only immutable values. The following sample is hypothetical, it doesn’t compile (due to value restriction) but nicely demonstrate the potential problems when mutability and side effects are allowed.

let v = ref None

Imagine that this piece of code is valid and v has type ref option<’T>. Then next few harmless statements will cause crash of application in runtime.

do v := Some 1
let r = defaultArg !v "A" // kaboom!!1 (we take int value from reference cell and try to treat it as a string)

Type checker thinks that these statements are perfectly correct because v is polymorphic. Luckily F# doesn’t let this happen and it is achieved by the value restriction.

Value restriction

The idea behind the solution is pretty simple; we need to divide all let bindings into two groups: first – that can be polymorphic and second – that should be bound to one particular type. The principle of splitting is based on the syntactic definition of values, automatic generalization is performed only on syntactic functions and on simple immutable values. All other bindings are not classified as values and so cannot be automatically generalized, basically compiler will suffer from lack of sufficient type information in a non-generic construct. Some general samples:

// applying polymorphic function to polymorphic value
let v = id []
// partial application
let map_id = Seq.map id

// create object with constructor inferring of type arguments
type A<'T>() = class end
let v1 = A<_>()

// create object omitting type arguments
type A<'T>() = class end
let create<'T> = A<'T>()
let a = create

Note: these samples cover all cases from the MSDN library. Also there is an error in MSDN article: code from case 1 compiles and executes without any problems.

Taming value restriction

As we now know what causes value restriction then we have a number of solutions on the pockets.

  1. Compiler doesn’t have all necessary information regarding types of the expression – we can give him a hint by annotating types explicitly

    let v : int list = id []
    let map_id : string list -> string seq = Seq.map id

    type A<'T>() = class end
    let v1 = A<int>()

    let create<'T> = A<'T>()
    let a = create<string>

    Simple solution but non-efficient in general cases - we lose polymorphism

  2. It is possible to convert non-value to value (syntactic function) by performing eta-conversion

    // added fake unit argument
    let v () = id []
    // added l (list) argument
    let map_id l = Seq.map id l
  3. Sometimes value restriction can be removed by reordering code elements so missing type information can be obtained from latter usage.

    // comments annotates operations that helps type inference engine

    let v = id []
    let intList = 1::v // cons operation

    let map_id = Seq.map id
    let res = map_id [1;2;3] // particular type of list

    type A<'T>() =
    let mutable v = Unchecked.defaultof<'T>
    member x.Value
    with set(value) = v <- value

    let a = A<_>()
    a.Value <- 10 // type of property (and of entire type) is inferred from assigned value

    Note: This approach is often cannot be used in FSI sessions due to specific of FSI (type for input expressions should be inferred immediately).

  4. F# standard library offers very interesting possibility to run generalization process by applying GeneralizableValue attribute to so-called type functions. Type function is let binding with generic arguments and empty argument list. F# spec defines designation of type functions:

    Type functions are typically used for:

    • Pure functions that compute type-specific information based on the supplied type arguments
    • Pure functions whose result is independent of inferred type arguments, e.g. empty sets and maps

    Type function can be annotated either with RequireExplicitTypeArgumentsAttribute (generic arguments should be set explicitly) or GeneralizableValueAttribute (generic arguments will be inferred).

    type A<'T>() = class end
    [<GeneralizableValue>]
    let create<'T> = A<'T>()
    let r = create
    printfn "%s" (r.GetType().FullName)

    Combination of type function and GeneralizableValueAttribute can be very confusing. Imagine:

    [<GeneralizableValue>]
    let none<'T> : 'T option ref = ref None

    The fact that none can be used without type parameters makes it appear like simple value. Don’t let this view fool you – this is function that returns new ref to None on every call.

    printfn "%O" (Option.isNone !none) // true
    none := Some(1)
    printfn "%O" (Option.isNone !none) // true

воскресенье, 18 апреля 2010 г.

MailboxProcessors: Practical Application

Last time we have examined the API of MailboxProcessors. Now it is time to see, how this concept can be applied to solve real-world problems.

Just as a quick reminder - "ping-pong" sample: two mailboxes, first one sends Ping request to second one, second replies with Pong. After specified number of iteratons execution stops.

type Message = Ping of AsyncReplyChannel<unit> | Stop

let pong (inbox : MailboxProcessor<Message>)=
let rec loop = async {
let! msg = inbox.Receive()
match msg with
| Ping(reply) ->
reply.Reply()
return! loop
| Stop -> ()
}
loop
let ping = MailboxProcessor.Start(fun (inbox : MailboxProcessor<int>) ->
let rec start () = async {
printfn "ping::waiting for number of iterations..."
let! n = inbox.Receive()
printfn "ping::%d received, start sending ping" n
do! loop n (MailboxProcessor.Start(pong))
}
and loop n (pong : MailboxProcessor<Message>) = async {
if n > 0 then
printfn "ping::sending ping, %d remaining" n
do! pong.PostAndAsyncReply(Ping)
printfn "ping::pong received"
do! loop (n - 1) pong
else
printfn "ping::exiting"
pong.Post(Stop)
}
start ()
)
ping.Post(5)
(*
ping::waiting for number of iterations...
ping::5 received, start sending ping
ping::sending ping, 5 remaining
ping::pong received
ping::sending ping, 4 remaining
ping::pong received
ping::sending ping, 3 remaining
ping::pong received
ping::sending ping, 2 remaining
ping::pong received
ping::sending ping, 1 remaining
ping::pong received
ping::exiting
*)

As opposed to trivial Pong function, Ping has a noteworthy moment, it defines a simple state machine with two states. First - obtaining for number of iterations, second - sending ping and waiting for reply.

Ping-pong sample fits nice for demo purposes but suffers from grave shortcoming - it is purely synthetic and useless in real life. It would be very nice to see the sample where MailboxProcessors can uncover their power and capabilities...

Web Sockets

The Web sockets specification - developed as part of the HTML5 initiative - introduced the Web Socket JavaScript interface, which defines a full-duplex single socket connection over which messages can be sent between client and server. The Web Socket standard attempts to simplify much of the complexity around bi-directional web communication and connection management.

The idea behind Web Sockets is very simple - client initiates TCP connection and performs handshake with server. After successful completion of handshake web sockets works pretty similar to usual sockets. Data is sent in the form of UTF-8 text. Frame can contain data where high bit is not set (0x00 to 0x7F) - this kind id data is transferred as a stream of bytes started with 0x00 and terminated with 0xFF. If high bit in data is set then this data should have leading length indicator which is encoded as a series of 7-bit bytes stored in octets with the 8th bit being set for all but the last byte.

For demonstration we will create simple web socket server that accepts requests from browser (Google Chrome already supports web sockets so it will be out test animal) and periodically sent JSON-encoded messages with current time information.

Server components.

Server
  • Request dispatcher accepts incoming connections and spawns worker to handle client requests
  • Worker sends and receives messages from particular client. Worker also incapluates all transport/serialization details so external components just post messages to worker.
  • Controller maintains list of workers and broadcasts messages.
  • Timer periodically send messages to Controller.
open System
open System.IO
open System.Net
open System.Net.Sockets
open System.Text
open System.Threading
open System.Runtime.Serialization

[<DataContract>]
type Time =
{ [<DataMember(Name = "hour")>] mutable Hour : int
[<DataMember(Name = "minute")>] mutable Minute : int
[<DataMember(Name = "second")>] mutable Second : int }
static member New(dt : DateTime) = {Hour = dt.Hour; Minute = dt.Minute; Second = dt.Second}

type Msg =
| Connect of MailboxProcessor<Time>
| Disconnect of MailboxProcessor<Time>
| Tick of Time

let startMailboxProcessor ct f = MailboxProcessor.Start(f, cancellationToken = ct)

let timer (ctrl : MailboxProcessor<Msg>) interval = async {
while true do
do! Async.Sleep interval
ctrl.Post(Tick <| Time.New(DateTime.Now))
}

let runController (ct : CancellationToken) = startMailboxProcessor ct (fun (inbox : MailboxProcessor<Msg>) ->
let listeners = new ResizeArray<_>()
async {
while not ct.IsCancellationRequested do
let! msg = inbox.Receive()
match msg with
| Connect l -> listeners.Add(l)
| Disconnect l -> listeners.Remove(l) |> ignore
| Tick msg -> listeners.ForEach(fun l -> l.Post msg)
}
)

let runWorker (tcp : TcpClient) (ctrl : MailboxProcessor<Msg>) ct = ignore <| startMailboxProcessor ct (fun (inbox : MailboxProcessor<Time>) ->
let rec handshake = async {
let ns = tcp.GetStream()
let reader = new StreamReader(ns)
let lines =
reader.ReadLine()
|> Seq.unfold(fun l -> if String.IsNullOrEmpty l then None else Some(l, reader.ReadLine()))
|> Seq.toArray

match lines with
| [| "GET /timer HTTP/1.1"; "Upgrade: WebSocket"; "Connection: Upgrade"; _; _|] ->
// TODO : parse WebSocket-Origin and WebSocket-Location

// send server handshake part
let serverHandshakePart =
"HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: file://
WebSocket-Location: ws://localhost/timer

"B
do! ns.AsyncWrite(serverHandshakePart)
return! run ns
| _ ->
//validation failed - close connection
tcp.Close()
}
and run (ns : NetworkStream) = async {
let json = System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof<Time>)
ctrl.Post(Connect inbox)
try
while not ct.IsCancellationRequested do
let! time = inbox.Receive()

let ms = new MemoryStream()
json.WriteObject(ms, time)

do ns.WriteByte(byte 0x00)
do! ns.AsyncWrite(ms.ToArray())
do ns.WriteByte(byte 0xFF)
finally
ns.Close()
ctrl.Post(Disconnect inbox)
}
handshake
)

let runRequestDispatcher () =
let listener = new TcpListener(IPAddress.Loopback, 80)
let cts = new CancellationTokenSource()
let token = cts.Token

let controller = runController token
Async.Start (timer controller 1000, token)

let main = async {
try
listener.Start(10)
while not cts.IsCancellationRequested do
let! client = Async.FromBeginEnd(listener.BeginAcceptTcpClient, listener.EndAcceptTcpClient)
runWorker client controller token
finally
listener.Stop()
}

Async.Start(main, token)

{ new IDisposable with member x.Dispose() = cts.Cancel()}

let dispose = runRequestDispatcher ()
printfn "press any key to stop..."
Console.ReadKey() |> ignore
dispose.Dispose()

index.html

<html>
<head>
<script>
ws = new WebSocket("ws://localhost/timer");
ws.onopen = function() { alert("Opened"); };
ws.onclose = function() { alert("Closed"); };
ws.onmessage = function(evt) {
var date = eval('(' + evt.data + ')');
hour.innerText = date.hour;
minute.innerText = date.minute;
second.innerText = date.second;
};
</script>
<style type="text/css">
table, td, th
{
font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;
border:1px solid #A7C942;
padding:3px 7px 2px 7px;
text-align:center;
}
td
{
font-weight:bold;
font-size:20px;
}
th
{
font-size:14px;
font-style:italic;
background-color:#A7C942;
color:white;
}
</style>
</head>
<body>
<table>
<tr>
<th>Hour</th>
<th>Minute</th>
<th>Second</th>
</tr>
<tr>
<td id="hour"></td>
<td id="minute"></td>
<td id="second"></td>
</tr>
</table>
</body>
</html>

I've opened 3 Chrome windows thus creating 3 workers. As we can notice that timer values in all browsers are changed simultaneously

p1

p2

 p3

понедельник, 12 апреля 2010 г.

MailboxProcessors: Erlang-style concurrency in F#

Erlang is the language designed by Ericsson with primary application domain: distributed, fault-tolerant applications. The basic concurrency-related unit in Erlang - lightweight process. These processes has nothing similar with processes of OS, but rather green threads. Processes comminicate by asynchronous copy-nothing message-passing: every process has associated mailbox with messages yet consumed and messages can be retrieved from mailbox without preserving original order of receiveing. Creation and destruction of process is very fast and number of coexisting processes in running system can be large (up to 20 million). The essential feature is giving one process ability to monitor state of another process so processes can form a hierarchy of workers and supervisors.

Concurrency style applied in Erlang is very natural for human pattern of thought (it is well described in Chapter 7 "Concurrency" of "Programming Erlang : Software for a concurrent world" by Joe Armstrong) so it is not surprising that libraries emulating such style exists in many languages: Scala Actors, Retlang (C#). Axum (MS Research incubation project) is based on the actor model. F# is not exception, its standard library includes MailboxProcessor - the hero of todays post.

MailboxProcessor is combination of message queue and message handler build atop of Asyncs infrastructure. It is usually created with MailboxProcessor.Start method though you can invoke constructor directly . Static method Start is just a shortcut that subsequently calls the constructor and instance Start method. Instance Start method starts execution of handler using thread from ThreadPool. Parts (//1) and (//2) in the sample below are equvalent.

let body = fun (_ : MailboxProcessor<int>) -> async {return ()}

// 1
MailboxProcessor.Start(body)

// 2
let mbp = new MailboxProcessor<_>(body)
mbp.Start()

Further samples will be written with (1) to make the declaration shorter. Both versions of Start method accept optional parameter cancellationToken to cancel execution of handler body.

Mandatory parameter body is the main workhorse of message handler. This function accepts MailboxProcessor<_> ( in runtime this will be reference to instance of MailboxProcessor associated with this handler).

mailboxprocessor

Blue bordered reference is the point for sending messages in mailbox. Green bordered one is used in handler to receive messages (though it is not prohibited to send message to itself)

MailboxProcessor.Start(fun (inbox : MailboxProcessor<int>) ->
async {
printfn "Sending..."
inbox.Post(10)
let! r = inbox.Receive()
printfn "Received %d" r
}
)
(*
Sending...
Received 10
*)

We can split members of MailboxProcessor according to common usage scenarios.

Methods that send message to MailboxProcessor

  • Post - asynchronously posts message in MailboxProcessor message queue.
  • Synchronous send
    • PostAndReply - synchronously sends message to MailboxProcessor and awaits for reply. Argument buildMessage should return the message with attached replyChannel. Receiver (MailboxProcessor) sends reply through provided reply channel. PostAndReply optionally accept timeout parameter. If reply wasn't received after timeout expiration then TimeoutException is raised
    • TryPostAndReply - similar to PostAndReply but returns None if method doesn't return in given timeout
  • Asynchronous send
    • PostAndAsyncReply - sends message to MailboxProcessor and returns computation that await the reply. Timeout behavior is the same with PostAndReply
    • PostAndTryAsyncReply - similar to PostAndAsyncReply but returns None if methods doesn't return in given timeout
let print fmt = Printf.ksprintf (fun s -> printfn "%s: %s" (System.DateTime.Now.ToString("hh::mm:ss")) s) fmt 
type Message = Async of int | Sync of int * AsyncReplyChannel<int>

let run1 () = MailboxProcessor.Start(fun (inbox : MailboxProcessor<Message>) ->
async {
while true do
let! msg = inbox.Receive()
match msg with
| Async(v) ->
print "async::%d" v
| Sync(v, reply) ->
print "sync::%d" v
do! Async.Sleep(v)
reply.Reply (v + 1)
}
)
let run2 (other : MailboxProcessor<Message>) = MailboxProcessor.Start(fun (inbox : MailboxProcessor<int>) ->
async {
let! timeout = inbox.Receive()
print "sending with timeout %d" timeout
let! value = other.PostAndAsyncReply(fun reply -> Sync(timeout, reply))
print "received %d" value
print "sending with timeout 1"
let! r = other.PostAndTryAsyncReply((fun reply -> Sync(timeout, reply)), timeout = 1)
match r with
| Some(_) -> print "some"
| None -> print "none"
}
)
let a = run1 ()
let b = run2 a

a.Post(Async 1000)
let r = a.PostAndReply(fun reply -> Sync(3000, reply))
print "received %d" r
b.Post(1000)
(*
// message is send directly to mailbox
05::10:58: async::1000 // async post
05::10:58: sync::3000 // sync post
05::11:01: received 3001 // result received after 3 seconds
// message is send from the handler of another mailbox
05::11:01: sending with timeout 1000 // sync send
05::11:01: sync::1000
05::11:02: received 1001 // success
05::11:02: sending with timeout 1 // send with little timeout
05::11:02: sync::1000
05::11:02: none // timeout expired
*)

Remarks:

  1. We define two message types: Async that contains only value and Sync - with value and reply channel
  2. Asynchronous Post returns immediately (as expected)
  3. PostAndReply was suspended for 3 seconds until handler replies to given channel.
  4. PostAndAsyncReply and PostAndTryAsyncReply can be used from async workflows, i.e. from the handler of another mailbox.
  5. PostAndTryAsyncReply on timeout returns None without throwing exception (as expected)

Receive methods.

  • Receive and TryReceive - both methods return computation that receives first message in message queue. The difference lies in the way of processing timeout: Receive throws TimeoutException and TryReceive returns None. By default timeout value is Timeout.Infinite but it can be changed with DefaultTimeout property.

I've already shown some samples with successful completion of Receive, now it is time to demonstrate the failures:

// 1
MailboxProcessor.Start(fun (inbox : MailboxProcessor<int>) ->
async {
printfn "1"
let! r = inbox.TryReceive(timeout = 1)
match r with
| Some _ -> printfn "some"
| None -> printfn "none"
printfn "2"
return()
}
)
|> ignore
(*
1
none
2
*)

// 2
MailboxProcessor.Start(fun (inbox : MailboxProcessor<int>) ->
async {
printfn "1"
try
do! inbox.Receive(timeout = 1) |> Async.Ignore
with
e -> printfn "%O" e
printfn "2"
return()
}
)
|> ignore
(*
1
>
System.TimeoutException: Mailbox.Receive timed out.
at <StartupCode$FSharp-Core>.$Control.processFirstArrival@1984-5.Invoke(Boolean _arg1024)
at Microsoft.FSharp.Control.AsyncBuilderImpl.args@720.Invoke(a a)
2
*)

// 3
let mbp = new MailboxProcessor<_>(fun (inbox : MailboxProcessor<int>) ->
async {
printfn "1"
do! inbox.Receive(timeout = 1) |> Async.Ignore
printfn "2"
return()
}
)
mbp.Error.Add(printfn "%O")
mbp.Start()

(*
1
>
System.TimeoutException: Mailbox.Receive timed out.
at <StartupCode$FSharp-Core>.$Control.processFirstArrival@1984-5.Invoke(Boolean _arg1024)
at Microsoft.FSharp.Control.AsyncBuilderImpl.args@720.Invoke(a a)
*)


Note: if exception is raised inside the handler you can either capture it explicity (// 2) or subscribe to Error event (// 3). In latter case handler body is terminated and only after that event is raised so you won't have chance to recover.

Message queue state

  • CurrentQueueLength - returns number of unprocessed messages in message queue. Note that in concurrent environment you should not strongly rely on this value because it can be quickly changed.
let mbp = MailboxProcessor.Start(fun (inbox : MailboxProcessor<int>) ->
async {
while true do
do! Async.Sleep 3000
printfn "number of messages: %d" inbox.CurrentQueueLength
}
)
(*

val mbp : MailboxProcessor<int>

> number of messages: 0
number of messages: 0
mbp.Post(1);;
val it : unit = ()
> number of messages: 1
number of messages: 1
mbp.Post(2);;
val it : unit = ()
> number of messages: 2
mbp.Post(3);;
val it : unit = ()
> number of messages: 3
number of messages: 3
number of messages: 3
*)

Selective receive

In small systems you can control the order of sending/receiving messages, but large systems makes this very difficult. When huge amount of concurrent paticipants are involved in process then messages can come into mailbox into unexpected order. In this case possibility to selectively receive message become essential. I'll demonstrate it on the small sample. Imaging you create supervisor process that spawns a number of children and waits messages from them in a strongly specified order, so we can illustrate state transitions with the following diagram

states

But what happens if process B will send completion signal before process A. We cannot ignore it because in this case we will wait in the third state forever. Gladly Erlang offers a brilliant feature named selective receive. Source code for supervisor transitions is below:

-module(selective_receive).
-export([waitA/0, waitB/0]).

waitA() ->
receive
{a, N} ->
io:format("received A ~w~n", [N]),
waitB()
end.
waitB() ->
receive
{b, N} ->
io:format("received B ~w~n", [N])
end.

sr

F# supports selective receive through two methods


  • Scan and TryScan - Scan/TryScan accepts scanner function and returns computation that applies scanner to all elements in message queue and returns on the first Some result. Matched element is removed from the queue. If after timeout expiration no element is matched, Scan throws TimeoutException and TryScan returns Async with None value.

    type Message = A of int | B of int

    let p = MailboxProcessor.Start(fun (inbox : MailboxProcessor<_>) ->
    let rec waitA = async {
    let! msg = inbox.Scan(function A(v) -> Some (async.Return v) | _ -> None)
    printfn "Received A %d" msg
    return! waitB
    }
    and waitB = async {
    let! msg = inbox.Scan(function B(v) -> Some(async.Return v) | _ -> None)
    printfn "Received B %d" msg
    }
    waitA
    )

    printfn "Posting B"
    p.Post(B 100)
    printfn "Posting A"
    p.Post(A 100)
    (*
    Posting B
    Posting A
    Received A 100
    Received B 100
    *)

You possibly have already noticed that scanner returns Async<'T> not 'T, so we need to wrap v into Async. Thought this approach is generic (it is possible to refer another async workflow inside returned result) it is not very handy in a large number of scenarios when you need just to select message. I'll be glad to see another overload of Scan with simplified scanner in the standard library.

type Message = A of int | B of int
type Microsoft.FSharp.Control.MailboxProcessor<'T> with
member this.Scan(scanner : 'T -> 'R option, ?timeout) =
this.Scan(
(fun v -> match scanner v with None -> None | Some(v) -> Some (async.Return v)),
?timeout = timeout
)


let p = MailboxProcessor.Start(fun (inbox : MailboxProcessor<_>) ->
let rec waitA = async {
let! msg = inbox.Scan(function A(v) -> Some (v) | _ -> None)
printfn "Received A %d" msg
return! waitB
}
and waitB = async {
let! msg = inbox.Scan(function B(v) -> Some(v) | _ -> None)
printfn "Received B %d" msg
}
waitA
)

printfn "Posting B"
p.Post(B 100)
printfn "Posting A"
p.Post(A 100)
(*
Posting B
Posting A
Received A 100
Received B 100
*)

What I would like to change/add/...

  1. I think that method names can be more descriptive. I don't mean simple ones (Post and Receive) but rather creepy things like PostAndTryAsyncReply or TryPostAndReply or PostAndAsyncReply. I am always confused with mix of all these Post, Try, Async, and Reply components so I propose to rename PostAndReply to Send and change names of remaining methods accordingly. Combination of Send and Post is often occured in different .NET API and meaning of each method is clearly defined: Send is synchronous version and Post - asynchronous.


    NowProposed
    Post Post
    PostAndReplySend
    TryPostAndReplyTrySend
    PostAndAsyncReply SendAsync
    PostAndTryAsyncReply TrySendAsync


  2. Process hierarchies is a very interesting way for handling faults in a large systems, you can program worker code to handle the correct scenario and rely on supervisor in case of errors. Scala has framework Akka that utilized the same principles of fault tolerance. However it is non-trivial for now to apply this approach to F# mailbox processors. The simpliest case: for example one process spawns another and subscribes its on Error event. If child process occasionaly dies parent receives the notification with exception...in the ex-child thread. The question arises: how to propagate exception into parent thread. The simplies solution is store exception in private field and reraise on the first call to MailboxProcessor (i.e Receive). However handler utilizes MailboxProcessor directly and members of MailboxProcessor are not virtual so I need to create wrapper, redefine handler in the terms of trapper and delegate all calls to actual MessageProcessor checking the exception field beforehand. Such solution is possible but it will be better if MailboxProcessor can initially support structuring them in hierarchies with unidirectional and bidirectional links.

  3. Separate interface of MailboxProcessor to sender and receiver parts so receiving can only be made from inside the handler

пятница, 2 апреля 2010 г.

Evoking by "Patterns of Parallel Programming" 1.1

In previous post I've made the sketch of Async.Any method, however code in sample should not be treated as a real-world implementation but rather as a demonstration of approach. Now we will improve existing version so the interest to it can be switched from academical to practical. Many thanks to Dmitry Lomov, as he reveals number of very serious flaws.

Let's list all imperfections of current solution:

  1. User continuation was invoked under the lock as well as (possibly) registered cancellation handlers
  2. CancellationTokenSource is not disposed after finishing the computation
  3. Exceptions are not handled at all
  4. All computations are executed in new fresh thread instead of enqueueing job to ThreadPool
  5. Base computation can already have ambient cancellation token and for now this token is ignored.

And now without further ado I'm glad to present you new version:

open System.Threading

type Async with
static member Any(asyncs : seq<Async<'T>>) =
let arr = Seq.toArray asyncs

// signals cancel only once, subsequent calls are ignored
// returns true if cancel signal issued; otherwise - false
let cancel cancelled (cts : CancellationTokenSource) =
if Interlocked.CompareExchange(cancelled, 1, 0) = 0
then cts.Cancel(); true
else false

let createComputation cancelled (cts : CancellationTokenSource) = Async.FromContinuations(fun (cont, econt, ccont) ->

let remaining = ref (int64 arr.Length)
if !remaining = 0L then failwith "Sequence should contain at least one computation"

let cancelled = ref 0

// decrements number of active computations
// disposes cancellation token source when last computation ends
// returns true if Dispose is called; otherwise - false
let decrement () =
if Interlocked.Decrement(remaining) = 0L
then cts.Dispose(); true
else false

let exceptions = new ResizeArray<_>()

let saveSuccess v =
if cancel cancelled cts
then
decrement() |> ignore
cont v
else
decrement() |> ignore

// stores exception
// calls error econt if all subcomputations were completed with errors
let saveError ex =
lock exceptions (fun () -> exceptions.Add(ex))
if decrement() && (exceptions.Count = arr.Length) then
econt(new System.AggregateException(exceptions))

for c in arr do
Async.StartWithContinuations(
async {
do! Async.SwitchToThreadPool()
return! c
},
saveSuccess,
saveError,
(fun _ -> decrement() |> ignore),
cancellationToken = cts.Token
)
)
async {
let cancelled = ref 0
let cts = new CancellationTokenSource()
use! d = Async.OnCancel(fun() -> cancel cancelled cts |> ignore)
let! r = createComputation cancelled cts
return r
}

Notes:

  1. cancel function can be called multiple times. First time leads to triggering cancellation on specified CancellationTokenSource,subsequent calls are ignored. When success continuation (saveSuccess) is invoked for the first time - it signals cancellation and delegates actual continuation.
  2. decrement function counts down when every computation ends (independently from completion type). Finally it disposes associated CancellationTokenSource.
  3. Async.OnCancel propagates externally signalled cancellation to nested computations.
 
GeekySpeaky: Submit Your Site!