WebSharper
By Adam Granicz on Friday, November 26, 2010 — 0 comments

WebSharper 2.0 Beta availableCore team

We are making excellent progress on releasing WebSharper 2.0 in the coming weeks, and have just put out the first beta version of WebSharper 2.0, ready for some public testing and community feedback. Here are the links (BE AWARE that these may become stale as new beta versions are released, so ALWAYS check the main WebSharper page for the latest download links):

Keep in mind that these are BETA releases, and may and probably do contain bugs and have various issues. We are aware of a number of issues and are working on resolving those for the next Beta releases, but none of these should have any significant impact on your ability to test the current release.

Introducing WebSharper Manager

To work with WebSharper 2.0 and any of the upcoming premium extensions, a valid product license is required for each component on every development machine. We have trial and developer licenses, and soon will be announcing community and academic licenses also. These may be obtained and managed with a new utility program called the WebSharper Manager (WSM) - see the link for a separate installer above. At this time, WSM serves as a license manager - but we are adding functionality to equip it with support features such as filing tickets, viewing resolutions, updating components, scheduling updates, etc. We recommend that WSM is installed on every machine where you intend to develop with WebSharper (at this point there is no other way to activate installations) - it will prove invaluable in keeping the members of your development team informed about new WebSharper components and any support items and their resolutions. WSM itself needs no license to run.

Since the main activation site is not yet operational, we have installed a temporary activation site with "dummy data" for early insiders and folks testing. The address of this temporary activation site is baked into the Beta release of WSM. Once the regular Beta releases are available and the official activation site opened, there will be a matching WSM release and all activation data will be transferred to the live activation site.

Upon start, WSM will retrieve specific WebSharper product information from the configured activation site and display all known products and their activation status. Green items don't need a license, orange ones do, blue ones show those that are licensed already. You can obtain a license to any component (including WebSharper Professional) by requesting a trial license (30, 60, or 90 days, depending on the component) with a single click, or by entering a valid S/N you obtained one way or another.

What's in WebSharper 2.0 Beta?

We will be blogging extensively about the upcoming features in the next couple weeks, until then here is a short list of some of the main items:

  • Sitelets - the latest WebSharper feature. You can use sitelets to compose entire sites as first-class site values, even with embedded/composed client-side functionality, and use site-wide combinators to add behavior.
  • HTML providers - compose HTML reusing the capabilities of external frameworks (or default to jQuery)
  • Generalized formlets - plug in your own reactive framework such as RxJs or Flapjax (or default to our built-in one)
  • Unified flowlets and dependent formlets - to model complex UI interactions and transitions
  • Super-fine granularity for resource tracking - JavaScript resources are loaded automatically whenever they are needed, and only then (as opposed to dependencies coming from type/assembly level)
  • More F# and .NET coverage - seamlessly translate active patterns, units of measure, inheritance/interfaces, etc. to JavaScript
  • WebSharper Manager to help you explore and try out new WebSharper extensions/tools/libraries
  • WebSharper Sample Web Application (ASP.NET) - Visual Studio solution template
  • WebSharper Sample Web Application (ASP.NET MVC) - Visual Studio solution template
  • WebSharper Sample Web Application (Sitelets) - Visual Studio solution template

What about extensions?

WebSharper 2.0 will have a TON of new extensions available shortly after the WebSharper 2.0 release, coming in small waves to cover a wide range of third-party technologies, from advanced visualization to massive UI control sets.

WebSharper 2.0 itself comes bundled with a number of "core" extensions, so you can enjoy them immediately:

  • Web foundation (IntelliFactory.Html, IntelliFactory.JavaScript, IntelliFactory.Json, IntelliFactory.Formlet.Base, IntelliFactory.Reactive, etc.)
  • IntelliFactory.WebSharper.Dom
  • IntelliFactory.WebSharper.EcmaScript
  • IntelliFactory.WebSharper.Formlet
  • IntelliFactory.WebSharper.Html
  • IntelliFactory.WebSharper.JQuery

Where to send feedback

You can send us your feedback, bug reports, etc. at websharper-reports@, or use the Bug Submission page on this website. We look forward to hearing from you!

By Adam Granicz on Monday, November 15, 2010 — 0 comments

WebSharper talk at Sinergija 2010Core team

I will be giving a talk at Sinergija 2010, Community Track about web programming in F# and with WebSharper. This event is Belgrade, Serbia - here is the abstract if you are in the area:

Developing Web Applications with F# in VS 2010

In this session I will discuss how functional programming and Visual F# enables professional web developers to create robust, client-based web applications with stunning brevity, without writing a single line of JavaScript code. We will briefly look at alternatives for F#-based web development, and discuss real-life examples using F# and the WebSharper framework. WebSharper offers a uniform developer story to express client- and server-side code in F#, enables seamless RPC communication, and brings powerful functional programming concepts such as formlets and flowlets to solve many common problems of web programming.

See you there!

By Adam Granicz on Wednesday, November 3, 2010 — 0 comments

Announcing the London WebSharper User GroupCore team

With around 3,000 unique WebSharper Standard downloads in the past few months, interest in learning about WebSharper and functional web programming in F# is increasing tremendeously. There are many intriguing blog posts popping up everywhere about WebSharper and using it to showcase F# web applications. But the success story doesn't end there! There are great new features in our upcoming WebSharper Professional release that we believe will fundamentally change the way web programming is done and will open new frontiers to those who dare to enter this exciting and rewarding new world.

Therefore, it is with great excitement that we are thrilled to announce the first London WebSharper User Group - a forum for WebSharper professionals and enthusiasts based in London, UK to exchange ideas and experiences, and to serve as a major hub for furthering the interest in functional web programing. We sincerely hope that it will add significant value to our WebSharper user community.
If you happen to be around London any time soon you should definitely drop by for our meetings or listen in on some of our web casts that we will be hosting.
We would like to thank SkillsMatter for providing a regular venue for this user group and organizing the first, inaugural meeting to be held on November 22, 2010. Registration is free and now open on the SkillsMatter event site, please register early if you plan on attending.

By Vladimir Matveev on Tuesday, November 2, 2010 — 0 comments

WebSchemeCommunity

Generally speaking if you abstract away from the visual part, WebSharper applications are not so different from usual F# libraries. Knowing this fact we can make our life much easier, and we can get away with simply: creating and testing basic components as a part of console application and later converting them to a WebSharper library. So, shall we begin?

Our little Scheme (an actual subset of real Scheme) interpreter will consist of three parts:

  • Lexer - transforms source text (sequence of chars) into a sequence of tokens
  • Parser - produces language expressions based on a given token stream
  • Runtime – generic name for the remaining part, that includes an execution engine and a standard library (in our case few builtin functions)

As I already mentioned, all these pieces are UI agnostic so they can be put into separate assembly that will be referenced from both the test console host and the front end WebSharper application.

Lexer comes first. Step 1: define Token type and implement lexical analyzer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
type Token = 
    | Identifier of string
    | Quote      of Token
    | Number     of int
    | Boolean    of bool
    | String     of string
    | List       of Token list
module Lexer = 
     let private toString (chars : char list) = 
        chars |> List.fold (fun acc s -> string s + acc) ""

    let isDigit c = c >= '0' && c <= '9' 
    let isWhiteSpace c = c = ' ' || c = '\t' || c = '\r' || c = '\n'

    let getTokens (source : string) = 
        let rec getToken inList = function
            | [] -> 
                if inList 
                then failwith "syntax error (missing close bracket)" 
                else None, []
            | ')'::rest -> 
                if inList 
                then None, rest 
                else failwith "syntax error (missing open bracket)" 
            | '('::rest ->
                let l, rest = getList true rest
                Some (List l), rest
            | '\''::rest ->
                let t, rest = getToken inList rest
                match t with
                | Some t -> Some (Quote t), rest
                | None -> failwith "syntax error (invalid quotation)"
            | c::rest when isWhiteSpace c -> getToken inList rest
            | '-'::((c::_) as rest) when isDigit c ->
                let num, rest = getNumber rest
                Some (Number -num), rest
            | (c::_) as rest when isDigit c ->
                let num, rest = getNumber rest
                Some (Number num), rest
            | '#'::'t'::rest ->
                Some (Boolean true), rest                
            | '#'::'f'::rest ->
                Some (Boolean false), rest                
            | '"'::rest ->
                let s, rest = getString rest
                Some (String s), rest
            | rest ->
                let identifier, rest = getIdentifier rest
                Some (Identifier identifier), rest
        
        and getList counter l = 
            let rec impl acc (rest : char list) l = 
                match getToken counter l with
                | Some t, rest -> impl (t::acc) [] rest
                | None, rest -> List.rev acc, rest
            impl [] [] l
        
        and getNumber l = 
            let rec impl acc = function
                | c::rest when isDigit c ->
                    let value = int c - int '0'
                    impl (acc * 10 + value) rest
                | rest -> acc, rest
            impl 0 l
        
        and getString l = 
            let rec impl acc = function
                | [] -> failwith "syntax error (malformed string)"
                | '\\'::'"'::rest -> impl ('"'::acc) rest
                | '"'::rest -> (toString acc, rest)
                | x::rest -> impl (x::acc) rest
            impl [] l

        and getIdentifier l = 
            let rec impl acc = function
                | [] -> toString acc, []
                | (('('::_) as rest)
                | ((')'::_) as rest) -> toString acc, rest
                | c::rest when isWhiteSpace c -> toString acc, rest
                | c::rest -> impl (c::acc) rest
            impl [] l
        
        let rec impl l = 
            [
                match getToken false l with
                | Some t, r -> 
                    yield t
                    match r with
                    | [] -> ()
                    | rest -> yield! impl rest
                | None, _ -> ()
            ]
        source 
            |> fun s -> s.ToCharArray()
            |> List.ofSeq
            |> impl
  • For simplicity our implementation will support only integers (floats are out of the boat for now)
  • Lexer results are slightly more than just conversion from chars to tokens, final sequence is already folded on brackets (lists are represented not as sequence of tokens like LEFT_BRACKET, NUMBER...RIGHT_BRACKET, but as one token List containing nested tokens with brackets omitted).
  • getTokens internally consists of several smaller functions: getList repeatadly reads a sequence of tokens containing within '(' and ')' and getToken tries to read next the token. If this attempt is successful - it returns the token and the remaining part of the stream.

Watch the doors, next stop: parser. With pattern matching its creation becomes a straightforward task:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
type Expr = 
    | Bool      of bool
    | Number    of int
    | String    of string
    | Atom      of string
    | List      of Expr list
    | Var       of string
    | Apply     of Expr * Expr list
    | Lambda    of string list * Expr
    | If        of Expr * Expr * Expr option
    | Assign    of string * Expr
    | Cond      of (Expr * Expr) list * Expr option
    | Let       of (string * Expr) list * Expr
    | LetRec    of (string * Expr) list * Expr
    | Sequence  of Expr list
    | CallCC    of Expr

module Parser = 
    let rec private parse tokens = 
        match tokens with
        | Token.Identifier s -> Expr.Var s
        | Token.Number n -> Expr.Number n
        | Token.Boolean b -> Expr.Bool b 
        | Token.String s -> Expr.String s
        | Token.Quote t -> parseQuote t
        | Token.List(tokens) -> parseList tokens

    and private parseQuote = function
        | Token.Number n -> Expr.Number n
        | Token.Boolean b -> Expr.Bool b
        | Token.String s -> Expr.String s
        | Token.Quote _ -> failwith "quoted quotes not supported yet"
        | Token.Identifier id -> Expr.Atom id
        | Token.List l -> l |> List.map parseQuote |> Expr.List
    
    and private parseCond tokens = 
        let rec impl acc = function
            | [] -> List.rev acc, None 
            | [Token.List([Token.Identifier "else"; body])] -> 
                List.rev acc, Some(parse body)
            | Token.List([cond; body])::rest -> 
                let cond = parse cond
                let body = parse body
                impl ((cond, body)::acc) rest
            | x -> failwith "invalid 'cond' syntax"
        impl [] tokens
    
    and private parseList = function
        | Token.Identifier "begin"::rest -> 
            rest 
            |> List.map parse 
            |> Sequence        
        | Token.Identifier "cond"::body -> 
            parseCond body 
            |> Expr.Cond
        | [Token.Identifier "callcc"; body] ->
            parse body
            |> Expr.CallCC
        | Token.Identifier "lambda"::Token.List(formals)::body -> 
            let formals = parseFormals formals
            Lambda(formals, Sequence(parseMain body))
        | Token.Identifier "let"::Token.List(bindings)::body -> 
            parseLet bindings body Let
        | Token.Identifier "letrec"::Token.List(bindings)::body -> 
            parseLet bindings body LetRec
        | [Token.Identifier "if"; cond; ifTrue] -> 
            let cond = parse cond
            let ifTrue = parse ifTrue
            Expr.If(cond, ifTrue, None)
        | [Token.Identifier "if"; cond; ifTrue; ifFalse] ->
            let cond = parse cond
            let ifTrue = parse ifTrue
            let ifFalse = parse ifFalse
            Expr.If(cond, ifTrue, Some ifFalse)        
        | [Token.Identifier "set!"; Token.Identifier(var); value] -> 
            Expr.Assign(var, parse value)
        | proc::args -> 
            Expr.Apply(parse proc, List.map parse args)
        | x -> 
            failwith "unrecognized token sequence"
    and private parseFormals formals = 
        formals 
            |> List.map parse 
            |> List.map(function 
                | Expr.Var s -> s 
                | x -> failwith "formal parameter should be var"
                )
    and private parseLet bindings body f =
        let bindings = 
            bindings
            |> List.map(function 
                | Token.List([Token.Identifier name; value]) -> name, parse value 
                | x -> failwith "invalid binding structure"
                )
        let body = parseMain body
        f(bindings, Sequence body)
     
    and parseMain tokens = 
        [
            match tokens with
            | Token.List
                (
                [Token.Identifier "define"; Token.Identifier var; body]
                )::xs ->
                yield Assign(var, parse body)
                yield! parseMain xs
            | Token.List
                (
                Token.Identifier "define"
                ::Token.List(Token.Identifier var::formals)
                ::body
                )::xs ->
                let f = parseFormals formals
                let b = parseMain body |> Sequence
                yield Assign(var ,Lambda(f, b)
                yield! parseMain xs
            | x::xs -> 
                yield parse x
                yield! parseMain xs
            | [] -> ()
        ]
  • Bool, Number and String corresponds to literals found in source text
  • List contains values wrapped in a quoted list in the source such as '(...)
  • Apply denotes function application. First parameter should be a function, second - list of arguments
  • If - simple if-then expression with optional 'else' part
  • Cond - similar to if-elseif-elseif-else expression where 'else' can be omitted
  • Assign - corresponds to a 'setq' expression: it evaluates the value and stores it in the environment under the given name
  • Var - references a variable within the environment
  • Let and LetRec contains list of pairs (bindings from name to value) and body. Bindings are evaluated and stored in a newly created environment. Afterwards this environment is used to evaluate the body. Difference between let and letrec lies in fact that letrec bindings can be recursively defined (refer to themselves in their definition).
  • Sequence - just a list of expressions
  • CallCC - Special higher-order magic: argument should be procedure with one parameter. Runtime will evaluate this procedure with a current continuation as a parameter value

Final step: runtime. It is basically the heart of our implementation and thus I'd like to devote slightly more attention to this stage.

The execution environment will be represented as list of Frames, every frame stores its own set of values. Name lookup is performed in a hierarchical manner: if name is not found in a child frame -> try search in parent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    type EnvFrame = Dictionary<string, obj> // System.Collections.Generic...
    type Env = EnvFrame list

    let private tryFindFrame name (d : EnvFrame) =
        if d.ContainsKey name 
        then Some (d, d.[name])
        else None
    
    let makeEnv prevEnv content  =
        let d = new Dictionary<_, _>()
        for (name, value) in content do
            d.Add(name, value)
        d::prevEnv 

    let private get name (env : Env) = 
        match List.tryPick (tryFindFrame name) env with
        | Some(_, value) -> value
        | None -> failwith ("name '" + name + "' not found")

    let private set name value (env : Env) = 
        match List.tryPick (tryFindFrame name) env with
        | Some (frame, _) -> frame.[name] <- value
        | None ->
            match env with
            | h::_ -> 
                h.[name] <- value
            | [] -> failwith "empty env."

Programming in Scheme heavily relies on recursion, but unfortunately our target platform (JavaScript) doesn't support optimization of tail calls. As a solution we can utilize 'trampolines' - a technique when every step returns delayed next step, so recursion is automagically converted to using loops. Main characters:

  • Step – a function that returns the next Step as its evaluation result.
  • Cont - represents the computation process at given point
  • Function - function representation, accepts argument values and continuation to proceed with execution.
1
2
3
    type Step = Step of (unit -> Step) option // None - stop 
    type Cont = obj -> Step
    type Function = obj list -> Cont -> Step

This is top level evaluation loop. Here we start the evaluation of some specified expression with respect to the given environment. finalCont will receive final result of computation and store it in a local variable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    let evaluate env expr = 
        let result = ref null
        let ok = ref true
        let finalCont = fun o -> result := o; Step None
        
        let step = ref (evaluateExpression expr env finalCont)
        
        while !ok do
            let (Step s) = !step
            match s with
            | Some f -> // has next step
                step := f()
            | None ->   // completed!
                ok := false
        !result

Let's examine the computation process on the sample of a simple (+) function. In an ideal world the expression x + y (where x and y can be complex expressions themselves) will be transformed to the following sequence of continuations:

1
2
3
4
5
let rec eval (e : Expression) (k : Continuation) = ...
// finalCont - continuation that will accept the result
eval a (fun valueOfA -> 
    eval b (fun valueOfB -> 
        finalCont (valueOfA + valueOfB)))

This will work in F# but not in JavaScript (due to lack of tail call optimization). So instead of running subsequent computations in continuations we'll delay evaluation by wrapping them in thunks.

1
2
3
4
5
let thunk f = ... something that wraps f with fun () -(fun () -> f())

eval a (fun valueOfA -> // k1
    thunk(fun () -> eval b (fun valueOfB -> // k2 
        thunk(fun () -> finalCont (valueOfA + valueOfB)))))

Now result of every continuation will not be the value itself but rather a function that returns value. This is how the trampoline works: first you jump (by calling the eval a -> forward to continuation k1) then you land (because k1 returns delayed computation). The evaluation loop makes one more iteration and you jump and land again (running eval b -> continuation k2 -> delayed computation). We repeat this process until evaluation is completed. Everything works nicely but explicit managing of continuation looks awful from the internal sense of constructive laziness – too much manual work. Can we do something to make continuation passing ambient? Surely yes! Computation expressions to the rescue.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
module Scheme = 

    open System.Collections.Generic

    type Step = Step of (unit -> Step) option
    type Cont = obj -> Step
    type Function = obj list -> Cont -> Step
    
    type EnvFrame = Dictionary<string, obj>
    type Env = EnvFrame list

     let private tryFindFrame name (d : EnvFrame) =
        if d.ContainsKey name 
        then Some (d, d.[name])
        else None
    
    let makeEnv prevEnv content  =
        let d = new Dictionary<_, _>()
        for (name, value) in content do
            d.Add(name, value)
        d::prevEnv 

    let private get name (env : Env) = 
        match List.tryPick (tryFindFrame name) env with
        | Some(_, value) -> value
        | None -> failwith ("name '" + name + "' not found")

   let private set name value (env : Env) = 
        match List.tryPick (tryFindFrame name) env with
        | Some (frame, _) -> frame.[name] <- value
        | None ->
            match env with
            | h::_ -> 
                h.[name] <- value
            | [] -> failwith "empty env."
    
    let thunk f = f |> Some |> Step
    
    type ContBuilder () = 

        member inline this.Return (v) = fun (k : Cont) -> thunk (fun() -> k v)

        member inline this.ReturnFrom (v : Cont -> Step ) = v
        
        member this.Bind(c : Cont -> Step, f : obj -> Cont -> Step)  = 
            fun (rk : Cont) ->
                let c1 (v : obj) = 
                    let c2 = f v
                    thunk (fun() -> c2 rk)
                thunk(fun() -> c c1)

    let K = ContBuilder()
    let private callCC (f : Function) : Cont -> Step =
        fun (extK : Cont) ->
            let exit : Function = fun [arg] _ -> K.Return arg extK
            f [exit] extK
    
    let rec private evaluateExpression expr (env : Env) = 
        match expr with
            | Expr.List(values) -> 
                let rec impl acc l = 
                    match l with
                    | [] ->  K { return List.rev acc }
                    | v::rest -> K { 
                        let! res = evaluateExpression v env
                        return! impl (res::acc) rest 
                        }
                impl [] values
            | Expr.Atom atom -> 
                K { return atom }
            | Expr.Bool v -> 
                K { return v }
            | Expr.Number n -> 
                K { return n }
            | Expr.String s -> 
                K { return s }
            | Expr.CallCC proc ->
                K { 
                    let! func = evaluateExpression proc env
                    match func with
                    | :? Function as f -> return! callCC f
                    | x -> return! failwith "callCC argument should be function"
                }
            | Expr.Assign (name, v) -> 
                K {
                    let! value = evaluateExpression v env
                    set name value env
                    return null
                }
            | Expr.Cond (clauses, elseCase) ->
                let rec evalCond = function
                    | (cond, body)::xs, _ -> 
                        K { 
                            let! v = evaluateExpression cond env
                            if unbox v 
                            then return! evaluateExpression body env
                            else return! evalCond(xs, elseCase)
                        }
                    | [], Some(c) -> K { return! evaluateExpression c env}
                    | _ -> K { return null }
                K { return! evalCond (clauses, elseCase)}
            | Expr.Apply(f, args) ->
                K { 
                    let! boxedFunc = evaluateExpression f env
                    match boxedFunc with
                    | :? Function as f ->
                        let rec evalArgs acc = function
                            | [] -> K { return! f (List.rev acc) }
                            | x::xs ->  K { 
                                let! value = evaluateExpression x env
                                return! evalArgs (value::acc) xs
                                }
                        return! evalArgs [] args
                    | _ -> return! failwith "function expected"    
                }
            | Expr.If (cond, ifTrue, ifFalse) ->
                K { 
                    let! v = evaluateExpression cond env
                    if unbox v 
                    then return! evaluateExpression ifTrue env
                    else 
                        match ifFalse with
                        | Some f -> return! evaluateExpression f env
                        | None -> return null
                }
            | Expr.Lambda(formals, body) ->
                let apply args= 
                    let newEnv = 
                        List.zip formals args
                        |> makeEnv env
                    K { return! evaluateExpression body newEnv}
                K { return apply }
            | Expr.Let(bindings, body) ->
                let rec evalBindings acc = function 
                    | [] -> 
                        let newEnv = 
                            acc 
                            |> List.rev
                            |> makeEnv env
                        K { return! evaluateExpression body newEnv }
                    | (name, x)::xs -> K { 
                        let! v = evaluateExpression x env
                        return! evalBindings ((name, v)::acc) xs
                        }
                K { return! evalBindings [] bindings }
            | Expr.LetRec(bindings, body) ->
                let newEnv = 
                    bindings
                    |> List.map (fun (name, _) -> name, null)
                    |> makeEnv env
                let rec evalBindings acc = function 
                    | [] -> K { return! evaluateExpression body newEnv }
                    | (n, x)::xs -> K { 
                        let! v = evaluateExpression x newEnv
                        set n v newEnv
                        return! evalBindings (v::acc) xs
                        }
                K { return! evalBindings [] bindings }
            | Expr.Sequence(statements) ->
                let rec impl s = 
                    match s with
                    | [] -> K { return null } 
                    | [x] -> K { return! evaluateExpression x env }
                    | x::xs -> K { 
                        let! _ = evaluateExpression x env
                        return! impl xs
                        }
                K { return! impl statements } 
            | Expr.Var(name) ->
                K { return get name env }
    
    let evaluate env expr = 
        let result = ref null
        let ok = ref true
        let finalCont = fun o -> result := o; Step None
    
        let step = ref (evaluateExpression expr env finalCont)
        
        while !ok do
            let (Step s) = !step
            match s with
            | Some f ->
                step := f()
            | None ->
                ok := false
        !result

To make our description complete - builtin functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
module Functions = 
    
    let K = Scheme.K

    let private pack (f : Scheme.Function) = box f
    
    let private makeListFunction f = 
        (function | [v : obj] -> f (v :?> obj list)) |> pack

    let private makeBinary op = 
        fun args -> K { 
            return args 
                |> List.map unbox
                |> List.reduce op
        } |> pack   

    let builtins () = 
        [ 
          "+", makeBinary (+)
          "-", makeBinary (-)
          "*", makeBinary (*)
          "/", makeBinary (/)
          "or", makeBinary (||)
          "<", (fun [a; b] -> K { return unbox a < unbox b}) |> pack
          "=", (function 
                    | [] | [_]-> failwith "invalid args"
                    | [x; y] -> K { return x.Equals(y) }
                    | [x; y; z] -> K { return (x.Equals(y) && y.Equals(z)) } 
                    | _ -> failwith "not supported")
               |> pack
          "zero?", (fun [x] -> K { return unbox x = 0} ) |> pack
          "null?", (function
                    | [] -> K { return true}
                    | _  -> K { return false} ) |> makeListFunction
          "car", (function | x::_ -> K { return x } ) |> makeListFunction
          "cdr", (function | _::xs -> K { return xs } ) |> makeListFunction
        ] 
        |> Scheme.makeEnv []

That's all folks, now time to test our creation:

Now we have a working implementation, what should be done with it to make it accessible in a WebSharper web application

  • Add a reference to the IntelliFactory.WebSharper assembly
  • Annotate assembly with the WebSharper attribute

    1
    2
    3
    4
    
    open System.Runtime.CompilerServices
    
    [<assembly:IntelliFactory.WebSharper.WebSharper>]
    do()
  • Put [<IntelliFactory.WebSharper.JavaScriptAttribute>] and [<IntelliFactory.WebSharper.JavaScriptTypeAttribute>] to all functions and types in our library
  • Make some coffee, everything else is taken care of.

Main part is done but we still need a fancy front end: syntax highlighting and so on. CodeMirror library already includes syntax highlighter for Scheme, we just need to plug it in. So add a WebSharper project to our solution, remove basic WebSharper sample code and perform a few magical passes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
open IntelliFactory.WebSharper

type CodeMirrorResources() = 
    interface IResource with
        member this.Render(resolver, writer) = 
            Resource.RenderJavaScript(resolver.ResolveUrl("js/codemirror.js")) writer
            Resource.RenderJavaScript(resolver.ResolveUrl("js/mirrorframe.js")) writer
            Resource.RenderCss(resolver.ResolveUrl("js/docs.css")) writer

[<Require(typeof<CodeMirrorResources>)>]    
module CodeMirror = 
    
    type Editor = 
        [<Inline "$this.getCode()">]
        member this.Code : string = failwith "no dynamic invokation"

    type EditorOptions [<Inline "{}">]() =
        [<DefaultValue; Name "height">] 
        val mutable Height : string

        [<DefaultValue; Name "content">] 
        val mutable Content : string

        [<DefaultValue; Name "stylesheet">] 
        val mutable StyleSheet : string

        [<DefaultValue; Name "path">] 
        val mutable Path : string

        [<DefaultValue; Name "parserfile">] 
        val mutable ParserFile : string array

        [<DefaultValue; Name "autoMatchParens">] 
        val mutable AutoMatchParens : bool

        [<DefaultValue; Name "disableSpellcheck">] 
        val mutable DisableSpellcheck : bool

        [<DefaultValue; Name "lineNumbers">] 
        val mutable LineNumbers : bool
    
    [<Inline("new CodeMirror(CodeMirror.replace($node), $options)")>]
    let create (node : Dom.Element) (options : EditorOptions) : Editor = 
        failwith "no dynamic invokation"

Here we have created typed wrappers for CodeMirror editor and configuration options. Remaining part is little compared to the work we've already done. Main frontend code + formatting the evaluation result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
open IntelliFactory.WebSharper
open IntelliFactory.WebSharper.Html

open WebScheme

[<JavaScriptType>]
type WebSchemeUI() = 
    inherit Web.Control()

    [<JavaScript>]
    let rec toString (v : obj) = 
        match JOperators.TypeOf(v) with
        | JType.Boolean 
        | JType.Number
        | JType.String -> v.ToString()
        | JType.Function -> "<function>"
        | JType.Undefined -> "<null>"
        | JType.Object ->
            let result = 
                match v :?> obj list with
                | [] -> ""
                | l -> 
                    l 
                    |> Seq.map toString 
                    |> Seq.reduce (fun acc v -> acc + "," + v) 
            "[" + result + "]"

    [<JavaScript>]
    override this.Body = 
        let env = WebScheme.Functions.builtins () |> ref
        
        let options = 
            CodeMirror.EditorOptions(
                Height = "300px",
                StyleSheet = "js/schemecolors.css",
                ParserFile = [|"tokenizescheme.js"; "parsescheme.js"|],
                AutoMatchParens = true,
                DisableSpellcheck = true,
                LineNumbers = true,
                Path = "js/"
            )
        let text = TextArea[]
        let editor = ref None
        text |> OnAfterRender (fun n -> 
            editor := Some (CodeMirror.create n.Dom options)
            )

        let result = Div [Width "100%"; Class "output"]
        let appendResult (v : obj) cls = 
            let value = Div [ Span [Class (cls + " message")] -< [Text (toString v)]]
            result.Append(value)
            result.JQuery.ScrollTop(result.JQuery.Height()).Ignore

        let evaluate = 
            Button [Text "Evaluate"]
            |>! OnClick (fun _ _ ->
                let text = editor.Value.Value.Code
                try
                    let tokens = Lexer.getTokens text
                    let expressions = Parser.parseMain tokens
                    for e in expressions do
                        match Scheme.evaluate !env e  with
                        | null -> ()
                        | result -> appendResult result "success"
                with
                    e -> appendResult (e.ToString()) "error"
                )

        let clear = 
            Button [Text "Clear"]
            |>! OnClick (fun _ _ ->
                env := Functions.builtins()
                result.Clear()
            )
        Table [Width "100%"; Border "0.8"] -< 
        [ 
            TR [Height "300px"] -< [  TD [ text ] ]
            TR [TD [evaluate; clear] ]
            TR [Height "200px"] -< [TD [result] ]
        ]

Enjoy the results:

Notice that despite the large input parameter, sumall completed successfully. If we modify ContBuilder to make all evaluation eager - then the result will match our expectation:

Source code for this sample is available here. Enjoy :)

By Adam Granicz on Wednesday, October 6, 2010 — 0 comments

F# MVP Award - 2010Core team

I am very excited about my recent Microsoft MVP 2010 award for my work in F#, and I would like to thank everyone who has recommended me for receiving this award. Foremost, I would like to thank my colleagues, Anton Tayanovskyy, Joel Björnson, Diego Echeverri, Vladimir Matveev, Artyom Shalkhakov, our past colleagues, the F# team (Don Syme, Luke Hoban, James Margetson, Tim Ng, Brian McNamara, and the other members), the many-many F# community members (to only name a few and without any particular order: Chris Barwich, Robert Pickering, Antonio Cisternino, Jon Harrop, Rick Minerich, Kevin Hazzard, Chris Marinos, Talbott Crowell, Aaron Erickson, Ryan Riley, Daniel Mohl, Joel Pobar, Ted Neward, Amanda Laucher, and others), the Visual Studio and Languages people at Microsoft (in particular, Lisa Feigenbaum), and my regional MVP director Alessandro Teglia.

The Microsoft MVP Award recognizes exceptional technical community leaders from around the world who voluntarily share their high quality, real world expertise with others. Microsoft MVPs are a highly select group of experts representing technology's best and brightest who share a deep commitment to community and a willingness to help others. Worldwide, there are over 100 million participants in technical communities; of these participants, there are fewer than 4,000 active Microsoft MVPs.

There are fewer than 30 MVPs in Hungary, and around a dozen F# (via C#) MVPs worldwide.

By Adam Granicz on Thursday, September 30, 2010 — 0 comments

Tutorial: Implementing a shopping cart with WebSharperCore team

Last week I had a Community for F# talk on WebSharper where I presented a small WebSharper application to implement a client-based, persistent shopping cart, and I received numerous emails asking for the source code for that talk. So in this post I am going to show you the full source code and walk you through what I did to implement the shopping cart functionality. The code provided here should work on any existing 1.0.X installation, preferably on the latest 1.0.28 release.

What's so special about this implementation?

  • First of all, it's all done with F# code with minimal markup involved to implement a site master page.
  • It demonstrates how easily you can write entire web applications in F# and integrate seamlessly with ASP.NET.
  • Despite its shortness, this shopping cart implementation can handle multiple product categories and display various products under in each category.
  • It is implemented entirely in client-side code, except for the initial call to the server to fetch the available products and families. Therefore, adding to, or removing items from the shopping cart, and calculating the total sum is handled entirely on the client, without any server-side intervention. This makes the application fast and highly interactive.
  • The application demonstrates just how easily you can enlist external JavaScript libraries in your WebSharper applications, all with F# code.

Building a shopping cart - the parts needed

There are three main parts to this WebSharper application. First, you need a design for how the page should look, second you need a WebSharper binding for the chosen client-side persistency framework, and third you need the WebSharper code for the main functionality of the shopping cart. We will discuss each of these below.
To get started, you should create a new WebSharper application in Visual Studio. If you don't have WebSharper installed, you can search for the WebSharper Standard plugin in the Visual Studio Gallery (in Visual Studio 2010, go to Tools / Extension Manager, and search for WebSharper in the Online Gallery), or download WebSharper Standard from our web site directly.

The following screenshot shows how your solution will eventually look like in the Visual Studio Solution Explorer.

Step 1 - Getting the design done

With WebSharper Standard, the primary way to expose your WebSharper applications is via ASP.NET. You will see shortly how easily you can accomplish this. In this first step, however, you will create a basic master page and populate the web application project in your WebSharper solution with a couple pages.

First, note that I am showing an out-of-project design.html file in the WebApplication project. This I used to create a basic HTML layout page that will serve as my ASP.NET master page. I then took this design and transliterated it to the following master page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<%@ Master %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<!-- Head -->
<head id="Head1" runat="server">
    <title>Your site title</title>
    <link href="reset.css" rel="stylesheet" type="text/css" />
    <link href="site.css" rel="stylesheet" type="text/css" />
    <WebSharper:ScriptManager runat="server" ></WebSharper:ScriptManager>
</head>
<body>
    <form runat="server">
    <table>
        <tbody>
            <tr>
                <td colspan="2" id="menu">
                    <div>
                        <asp:HyperLink runat="server" NavigateUrl="~/Flowlet.aspx">
                            Flowlet</asp:HyperLink> |
                        <asp:HyperLink runat="server" NavigateUrl="~/ShoppingCart.aspx">
                            Shopping Cart</asp:HyperLink>
                    </div>
                </td>
            </tr>
            <tr>
                <td colspan="2" id="banner">
                    <asp:ContentPlaceHolder runat="server" ID="Title">
                    </asp:ContentPlaceHolder>
                </td>
            </tr>
            <tr>
                <td id="main">
                    <asp:ContentPlaceHolder runat="server" ID="Main">
                    </asp:ContentPlaceHolder>
                </td>
                <td id="side">
                    <asp:ContentPlaceHolder runat="server" ID="Side">
                    </asp:ContentPlaceHolder>
                </td>
            </tr>
            <tr>
                <td colspan="2" id="footer">
                    WebSharper™ demo by Adam Granicz, IntelliFactory.
                    Absolutely no warranty of any kind :)
                </td>
            </tr>
        </tbody>
    </table>
    </form>
</body>
</html>

I won't inline reset.css and site.css here, you can find them in the attachment zip file in the bottom of this article. As you would expect, the former implements some basic "reset" on the HTML styles, and the latter implements the look and feel for the mini-site.

The master page with a default instantiation looks like the following:

With this new master page, you can add a couple new pages and modify the default page to have links to both. Here is Flowlet.aspx - which wraps the SignupSequence pagelet (renamed to signup.fs in WebSharperProject) from the "default" WebSharper project that I left for the sake of having two different pages in our mini site:

1
2
3
4
5
6
7
8
9
<%@ Page MasterPageFile="~/site.master" %>

<asp:Content ContentPlaceHolderID="Title" runat="server">
    <h1>Flowlets Demo</h1>
</asp:Content>

<asp:Content ContentPlaceHolderID="Main" runat="server">
    <ws:SignupSequence runat="server" ></ws:SignupSequence>
</asp:Content>

Note that I did have to make a couple small changes in signup.fs from the default, namely I switched the formlet and flowlet declarations to be lazy, so I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[<JavaScript>]
let BasicInfoForm () : Formlet<BasicInfo> =
    ...

[<JavaScript>]
let ContactInfoForm () =
    ...

[<JavaScript>]
let SignupSequence () =
    ...

[<JavaScript>]
override this.Body = ContactForms.SignupSequence ()

These were necessary because the code in the default project template assumes that these formlets are created eagerly - that is for every pagelet inside your WebSharper application. However, in our shopping cart application this is not true - so you need to switch those formlet/flowlet constructions to be on demand.

The ShoppingCart.aspx file is just as simple as Flowlet.aspx, simply filling the content holes of the master page and exposing the two WebSharper controls (ItemsToBuy and ShoppingCart) we are about to develop.

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ Page MasterPageFile="~/site.master" %>

<asp:Content ContentPlaceHolderID="Title" runat="server">
    <h1>Your Shopping Cart</h1>
</asp:Content>

<asp:Content ContentPlaceHolderID="Main" runat="server">
    <ws:ItemsToBuy ID="ItemsToBuy1" runat="server" ></ws:ItemsToBuy>
</asp:Content>

<asp:Content ContentPlaceHolderID="Side" runat="server">
    <ws:ShoppingCart ID="ShoppingCart1" runat="server" ></ws:ShoppingCart>
</asp:Content>

Step II - Wrapping Persist.js

Before we develop the shopping cart functionality, we need an API for saving to and retrieving values from a client-side persistent storage. This machinery will give us the necessary functions to operate on the shopping cart state.

A quick look around the web for client-side persistent storage reveals several compeling choices. For one, we could use HTML5 Web Storage - however, its implementation is lagging behind in different browsers. Another alternative, PersistJs seems much more viable as it promises widespread backwards compatibility, so I decided to use that.

A quick look at the PersistJs samples reveals a very simple, to-the-point API. You can do three main things:

  • Create or fetch a new store by name
  • Save some string data at a given string key in a store.
  • Retrieve asynchronously the value assigned to some key in a store.

We will need to store arbitrary values in the store, so this API needs some slight adjustments as we migrate it over to WebSharper. For this, we need a way to marshal arbitrary values to strings and unmarshal them back to values of their appropriate type.

Below is the full implementation of the PersistJs WebSharper bindings (WebSharperProject/persistjs.fs):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
namespace IntelliFactory.WebSharper.PersistJs

open IntelliFactory.WebSharper

module internal JSON =

    [<Inline "JSON.parse($x)">]
    let Parse<'T> (x: string) : 'T = Unchecked.defaultof<'T>

module Dependencies =
    open System
    open System.Configuration
    open IntelliFactory.WebSharper

    let internal PersistJsBase =
        let key = "IntelliFactory.WebSharper.PersistJs"
        match ConfigurationManager.AppSettings.[key] with
        | null ->
            "/js/persist-js"
        | url ->
            url

    [<AbstractClass>]
    type JsResource(fname: string) =
        interface IResource with
            member this.Render (resolver, writer) =
                let loc = sprintf "%s/%s" PersistJsBase fname
                Resource.RenderJavaScript loc writer

    type PersistJs() = inherit JsResource("persist-min.js")

[<Require(typeof<Dependencies.PersistJs>)>]
[<JavaScriptType>]
type Store =
    [<Inline "new Persist.Store($name)">]
    static member Create (name: string) : Store =
        failwith "Client-side"

    [<Inline "$this.set($key, JSON.stringify($value))">]
    member this.Save<'T> (key: string, value: 'T) : unit =
        failwith "Client-side"

    [<Inline "$this.get($key, $callback)">]
    member private this.RetrieveP (key: string, callback: bool*string->unit) : unit =
        failwith "Client-side"

    [<JavaScript>]
    [<Inline>]
    member this.Retrieve<'T> (key: string) : Async<'T option> =
        Async.FromContinuations <| fun (onOk, onExc, onTerm) ->
            this.RetrieveP(key, fun (ok, str) ->
                if ok && str <> null then
                    onOk (Some (JSON.Parse<'T> str))
                else
                    onOk None)

    [<JavaScript>]
    [<Inline>]
    member this.Contains (key: string) : Async<bool> =
        Async.FromContinuations <| fun (onOk, onExc, onTerm) ->
            this.RetrieveP(key, fun (ok, str) ->
                if ok && str <> null then
                    onOk true
                else
                    onOk false)

In this code, the internal JSON module supplies the Parse member, this performs the unmarshalling needed for retrieving values from the store. Marshalling is inlined via the native JSON.stringify function.

While the above code is pretty straightforward, the Dependencies module deserves some mention. First, we define an abstract class that represents JavaScript resources relative to a base location. This base location defaults to the /js/persist-js folder on the web server, but can also be overriden via Web.Config. Finally, we define the persist-min.js (available from the PersistJs site) artifact as a JavaScript resource. Note how this resource is then annotated on the main Store type as a resource requirement. This causes the WebSharper script manager (that is present in our master page) to inline a reference to persist-min.js when this Store class is in use in the current page.

Part 3 - Implementing the shopping cart

Now you are ready to implement the main shopping cart functionality. This has two parts- a listing of available products broken down by category, and the shopping cart that summarizes the items already in the cart.

Below is a mockup of these two "controls" and the events that can originate from both.

Note that both the ItemsForSale and the ShoppingCart controls can originate events, but only the latter one can react to them visually. You can implement these events in a variety of ways. In my talk I mentioned several alternatives:

  • Implementing a simple message queue, such as a MailBox
  • Hosting ItemsToBuy and ShoppingCart in a parent pagelet and handling their communication locally in that pagelet
  • Using the upcoming RxJs bindings for WebSharper, and implementing the shopping cart as an observable collection via reactive programming
  • Using simple F# events - where both controls trigger various events, and the ShoppingCart control subscribes to the shared event channel and responds visually as appropriate

For this implementation I chose the last option, implementing the communication between the two pagelets using F# events. This is a strikingly simple yet effective approach that works perfectly on the client-side.

So without further due, let's jump into the main shopping-cart.fs module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
namespace WebSharperProject

open System
open IntelliFactory.WebSharper
open IntelliFactory.WebSharper.Html

module ShoppingCartInternals =
    module M = Microsoft.FSharp.Collections.Map

    module Internals =

        [<JavaScript>]
        let internal store () = PersistJs.Store.Create "shopping-cart-4"

        [<JavaScript>]
        let NextCounter () =
            let setCounterTo i =
                (store ()).Save<int>("counter", i)
            async {
                let! currOpt = (store ()).Retrieve<int> "counter"
                let current =
                    match currOpt with
                    | None ->
                        0
                    | Some curr ->
                        curr
                let res = current+1
                setCounterTo res
                return res
            }

        [<JavaScript>]
        let SetItemsInCart items =
            (store ()).Save<(string * (string*float*int*int)) array>("cart", items)

        [<JavaScript>]
        let GetItemsInCart () : Async<Map<string, (string*float*int*int)>> =
            let getCart () =
                (store ()).Retrieve<(string * (string*float*int*int)) array> "cart"
            async {
                let! res = getCart ()
                let newres =
                    match res with
                    | None ->
                        SetItemsInCart [||]
                        [||]
                    | Some items ->
                        items
                let res =
                    newres
                    |> M.ofArray
                return res
            }

The above code encapsulates the persistent storage-related functionality into the Internals module. Here, the internal store function creates or fetches a store by name, NextCounter supplies an increasing stream of numbers (implemented via storing the last "ticket" number in the persistent store) that you use for ordering items that are added to the cart (last added is shown last), SetItemsInCart, and GetItemsInCart store and retrieve all items in the cart, respectively (we do this as a batch operation since our PersistJs binding doesn't expose an API for enumerating all entries in a given store).

The events you saw earlier are modeled as a union type (CartEvent) and the main event channel (ShoppingCartEvents) is a simple F# first-class event that communicates CartEvent values:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    module Events =
        type Item =
            { ProductName : string
              Title: string
              Price: float }

        type CartEvent =
            | AddItem of Item * int
            | AddOneItem of string
            | RemoveOneItem of string
            | RemoveItem of string
            | EmptyCart

        [<JavaScript>]
        let ShoppingCartEvents = new Event<CartEvent> ()

The only time we need to contact the server is when we fetch the available products and their categories. This is encapsulated in the Server module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    module Server =
        type CartFamily =
            { Title : string
              Products : CartProduct list }

        and CartProduct =
            { Title : string
              ProductName : string
              ImageSrc : string
              Price : float }

        /// Computes the families and the products inside them that are
        /// available for download.
        [<Rpc>]
        let ComputeFamiliesAndProducts () : CartFamily list =
            let T imageSrc (title, id, price) =
                { Title = title
                  ProductName = id
                  ImageSrc = imageSrc
                  Price = price }
            let laptop prod = T "/images/laptop.png" prod
            let desktop prod = T "/images/desktop.png" prod
            let netbook prod = T "/images/netbook.png" prod
            [ { Title = "Laptops"
                Products =
                  [ laptop ("Toshiba", "id1", 1299.0)
                    laptop ("HP", "id2", 1499.0)
                    laptop ("Dell", "id3", 1499.0)
                    laptop ("Acer", "id4", 1499.0) ] }
              { Title = "Desktops"
                Products =
                  [ desktop ("Gamer 1", "id11", 699.0)
                    desktop ("Gamer 2", "id12", 799.0)
                    desktop ("Office", "id13", 599.0)
                    desktop ("Server", "id14", 1299.0) ] }
              { Title = "Netbooks"
                Products =
                  [ netbook ("Entry", "id21", 799.0)
                    netbook ("Medium", "id22", 899.0)
                    netbook ("Cool", "id23", 699.0)
                    netbook ("Speed-King", "id24", 999.0) ] } ]

Here, each product has a title that we display (such as "Dell"), a corresponding product name we use to identify the product (such as "id3"), a URL that points to the image that represents the product, and a price (we assume dollars).

You will also need a tiny utility function to create buttons:

1
2
3
4
5
    module WebControls =

        [<JavaScript>]
        let Button label =
            Input [Type "button"; Value label; Width (label.Length*15 |> string)]

With the internal, event-, and server-relared abstractions, you can now implement the actual client-side controls. The "design" for these controls is taken from our initial HTML mockup (design.html), transliterated into a nested HTML combinator structure with further F# code to populate it with actual data. The Client module has the function that is called when the user checks out - I left this function empty, but this is the place where you would normally process payment, etc.

1
2
3
4
5
    module Client =
        /// Sends payment.
        [<JavaScript>]
        let SendPayment (items: (string * (string*float*int*int)) list) =
            ()

The ItemsForSale control fetches all product families from the server and displays them.

1
2
3
4
5
6
7
8
9
        /// Displays all item categories and their items for sale.
        [<JavaScript>]
        let ItemsToBuy () =
            let families = Server.ComputeFamiliesAndProducts ()
            Div [Id "shopping-cart"] -< [
                families
                |> List.map (fun family ->
                    Div [Class "family"] -< [
                        H1 [Text family.Title]

For each family, you list all products therein by iterating through the Products collection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                        family.Products
                        |> List.map (fun product ->
                            let input = Input [Type "text"; Value "1"]
                            Div [Class "product"] -< [
                                Img [Alt product.Title; Src product.ImageSrc]
                                Div [
                                    H1 [Text product.Title]
                                    P [
                                        Code [Text ("$" + string product.Price)]
                                    ] -< [
                                        Text " / item"
                                    ]
                                    P [
                                        Text "Quantity:"
                                    ] -< [
                                        input
                                    ]

The "Add to cart" button triggers a CartEvent.AddItem event that carries the product data:

1
2
3
4
5
6
7
8
9
10
11
12
                                    WebControls.Button "Add to cart"
                                    |>! OnClick (fun e args ->
                                        Events.CartEvent.AddItem (
                                            { ProductName=product.ProductName
                                              Title=product.Title
                                              Price=product.Price },
                                            (int input.Value))
                                        |> Events.ShoppingCartEvents.Trigger
                                    )
                                ]
                            ]
                        )

Finally, you add a "closer" DIV to render each family nicely under one another.

1
2
3
4
5
6
7
8
9
                        |> fun products ->
                            products @ [
                                Div [Style "clear:both;"]
                            ]
                            |> Div
                    ]
                )
                |> Div
            ]

The ShoppingCart control is slightly more complex as it needs to handle the various events that come through the ShoppingCartEvents channel. But first, you define a placeholder for the shopping cart (contents), and a function that updates this placeholder with the items in the cart:

1
2
3
4
5
6
7
8
9
10
        /// Displays the shopping cart.
        [<JavaScript>]
        let ShoppingCart () =
            let contents = Div []
            let updateCart () =
                async {
                    let! itemsInCart = Internals.GetItemsInCart ()
                    contents.Clear ()
                    Div [Id "shopping-cart-contents"] -< [
                        H1 [Text "Shopping Cart"]

Each item in the cart will be displays as a row in a table. Furthermore, cart items are sorted by their order. You also need to the total cost of all items in the cart, so you fold through the sorted item list, with some minor logic to alternate row styles:

1
2
3
4
5
6
7
8
9
10
                        Table [
                            itemsInCart
                            |> M.toList
                            |> List.sortBy (fun (_, (_, _, _, order)) -> order)
                            |> List.fold (fun (i, acc, sum) (product, (t, p, q, o)) ->
                                let alt =
                                    if i%2 = 1 then
                                        "alt "
                                    else
                                        ""

For each item, you display a set of buttons, each firing their corresponding events, and accumulate the total cost:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
                                (i+1, acc @
                                 [
                                    TR [Class alt] -< [
                                        TD [Class "col1"] -< [
                                            WebControls.Button "-"
                                            // What happens when we click "-"?
                                            |>! OnClick (fun e args ->
                                                product
                                                |> Events.CartEvent.RemoveOneItem
                                                |> Events.ShoppingCartEvents.Trigger
                                            )
                                            Div [Class "count"] -< [q|>string|>Text]
                                            WebControls.Button "+"
                                            // What happens when we click "+"?
                                            |>! OnClick (fun e args ->
                                                product
                                                |> Events.CartEvent.AddOneItem
                                                |> Events.ShoppingCartEvents.Trigger
                                            )
                                            WebControls.Button "X"
                                            // What happens when we click "Remove"?
                                            |>! OnClick (fun e args ->
                                                product
                                                |> Events.CartEvent.RemoveItem
                                                |> Events.ShoppingCartEvents.Trigger
                                            )
                                            Div [Class "title"] -< [Text t]
                                        ]
                                        TD [Class "col2"] -< [
                                            Code [
                                                Text (string p)
                                            ]
                                        ]
                                    ]
                                 ], sum + (float q)*p)
                            ) (0, [], 0.)

Finally, you wrap up the items with displaying the totals:

1
2
3
4
5
6
7
8
9
10
11
12
                            |> fun (_, rows, sum) ->
                                rows
                                |> fun rows ->
                                    rows @ [
                                        TR [ Hr [] ]
                                        TR [
                                            TD [Text "Total:"]
                                            TD [Code [sum |> string |> Text]]
                                        ]
                                    ]
                                    |> TBody
                        ]

And last, you add the "Checkout" and "Empty cart" buttons - both clearing the cart contents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
                        Div [Style "height:20px"] -< []
                        Div [
                            WebControls.Button "Checkout"
                            |>! OnClick (fun e args ->
                                Window.Alert "Checkout!"
                                // Process payment
                                itemsInCart
                                |> M.toList
                                |> SendPayment
                                // Empty shopping cart
                                Events.CartEvent.EmptyCart
                                |> Events.ShoppingCartEvents.Trigger
                            )
                            WebControls.Button "Empty cart"
                            |>! OnClick (fun e args ->
                                Events.CartEvent.EmptyCart
                                |> Events.ShoppingCartEvents.Trigger
                            )
                        ]
                    ]
                    |> contents.Append
                }
                |> Async.Start

Handling the events that come through the event channel is done by subscribing to that event channel, matching on the various events that come in and do the right thing for each:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
            Events.ShoppingCartEvents.Publish.Add (fun ce ->
                async {
                    let! itemsInCart = Internals.GetItemsInCart ()
                    let! next = Internals.NextCounter ()
                    let SET items =
                        items |> M.toArray |> Internals.SetItemsInCart
                    let _ =
                        match ce with
                        | Events.CartEvent.AddItem (item, qty) ->
                            let qN, o =
                                if M.containsKey item.ProductName itemsInCart then
                                    let _, _, qO, o = itemsInCart.[item.ProductName]
                                    qO + qty, o
                                else
                                    qty, next
                            itemsInCart
                            |> M.add item.ProductName (item.Title, item.Price, qN, o)
                            |> SET
                        | Events.CartEvent.RemoveOneItem productName ->
                            if M.containsKey productName itemsInCart then
                                let t, p, q, o = itemsInCart.[productName]
                                if q <= 1 then
                                    itemsInCart
                                    |> M.remove productName 
                                else
                                    itemsInCart
                                    |> M.add productName (t, p, q-1, o)
                                |> SET
                        | Events.CartEvent.AddOneItem productName ->
                            if M.containsKey productName itemsInCart then
                                let t, p, q, o = itemsInCart.[productName]
                                itemsInCart
                                |> M.add productName (t, p, q+1, o)
                                |> SET
                        | Events.CartEvent.RemoveItem productName ->
                            itemsInCart
                            |> M.remove productName
                            |> SET
                        | Events.CartEvent.EmptyCart ->
                            M.empty
                            |> SET
                    do updateCart ()
                }
                |> Async.Start
            )

And finally, you display the cart contents and return the placeholder element:

1
2
            updateCart ()
            contents

Conclusion

In this tutorial, you saw how you can bind and use existing JavaScript libraries with WebSharper and implemented a client-based persistent shopping cart based on PersistJs. You used asynchronous workflows to model fetching values from the persistent store, and F# events for modeling the communication between two pagelets that made up your shopping cart application.

AbstractShoppingCart.zip

By Adam Granicz on Friday, August 6, 2010 — 0 comments

WebSharper available in Visual Studio GalleryCore team

WebSharper 2010 Standard is now available through Visual Studio Gallery, complementing among others the great F# templates from Daniel, and those announced in Don's earlier article.
You can either search for WebSharper in the Extension Manager (under Tools) in Visual Studio 2010, or go to the Gallery page directly.

Click Download, walk through the couple steps of the installer, and you are good to go. The Gallery page also provides a few quick pointers, but be sure to check out the WebSharper main page and the demos page to get started.

By Anton Tayanovskyy on Tuesday, June 29, 2010 — 0 comments

Optimizing JavaScript with F#Core team

These days WebSharper™ trenches are teeming with activity as we are busy preparing the next major release of the platform. One of the F#-to-JavaScript compiler highlights of the new release is a host of optimizations on the JavaScript output. Designing these optimizations with F# was quite rewarding, and I am sharing some of the eurekas in this blog.

The need for optimizing JavaScript is very peculiar. This is not about delivering top wall-clock performance, but rather delivering the most compact (in Release mode) and most readable (in Debug mode) source. In the case of WebSharper™, it is also about relieving the compiler and the macro writer from the burden of emitting optimal code. Essentially, we would like to conform to the Macro Writer's Bill of Rights, for JavaScript.
The optimizations covered today include:

  • constant folding
  • inlining
  • redex elimination
  • common subexpression elimination

The problem with optimizing JavaScript is that it is complex. There are expressions, statements, objects, field assignments and what not. Scoping of variables is not functional, there are no let statements (we target the 3rd edition of ECMA-262). Any of the above optimizations are non-trivial on the complete JavaScript AST.

For this and other reasons, we ended up designing an intermediate representation, Core JavaScript. Unlike complete JavaScript, Core JavaScript is functional, simple, and very easy to optimize. In fact, Core JavaScript expressions instantiate Core Scheme expressions parameterized by a primitive set. Here is the definition of a Core Scheme expression:

1
2
3
4
5
6
7
8
9
10
type Expression<'P> =
    | Apply of E<'P> * list<E<'P>>
    | Assign of Id * E<'P>
    | If of E<'P> * E<'P> * E<'P>
    | Lambda of list<Id> * E<'P>
    | Let of Id * E<'P> * E<'P>
    | LetRecursive of list<Id * E<'P>> * E<'P>
    | Primitive of 'P * list<E<'P>>
    | Undefined
    | Var of Id

The good news is that while Core JavaScript is fully as expressive and in fact very close to the complete JavaScript, we can now write optimizations as transformations on Core Scheme expressions that preserve the (simple) Scheme semantics. For example, common subexpression elimination looks for matching pure, ground subexpressions, and lifts them to a Let binding. And of course not having to deal with expression/statement distinction, this argument passing convention, and the like is the joy for the compiler or macro writer.
Example 1: Eliminating Common Subexpressions

1
2
3
4
5
6
7
let x = Id "x"
let y = Id "y"
let this = Id "this"
E.Array [
    E.Function this [x; y] (!^this .% !^x ..% [!^y])
    E.Function this [x; y] (!^this .% !^x ..% [!^y])
]

Note: ( !^ ) :: Id -> Expression lifts identifiers to expressions.
This outputs:

1
2
3
4
5
6
7
8
9
(function ()
 {
   var _;
   function _(x, y)
   {
     return this[x](y);
   }
   return [_, _];
 })()

Example 2: Inlining and Constant Folding

1
2
3
4
5
E.Let y (E.Int 1) (
    E.Let x (E.Int 2) (
        !^x +% !^y
    )
)

Outputs:

1
2
3
4
(function ()
 {
   return 3
 })()

Example 3: Redex Elimination and Constant Folding

1
2
E.Function this [x] (!^x +% E.String "!") 
    ..% [E.String "Hello"]

Outputs:

1
2
3
4
(function ()
 {
   return "Hello!"
 })()

Writing the optimizations was a joy. For example, the inlining transformation is within 20 lines of F#.

The largest contribution to the joy is the fact that the underlying engine takes care of JavaScript insanity.

For instance, using the same suggested variable names gives valid JavaScript code by disambiguating variables:

1
2
3
4
5
E.Let x (L?foo ..% []) (
   E.Let x (L?bar ..% [!^x]) (
      L?baz ..% [!^x]
   )
)

Outputs:

1
2
3
4
5
6
7
(function ()
 {
   var x, x1;
   x = foo();
   x1 = bar(x);
   return baz(x1);
 })()

As a final example, this-style variables are automatically handled when captured, for example:

1
2
3
4
5
E.Function this1 [] (
    E.Function this2 [] (
        !^this1 +% !^this2
    )
)

Outputs:

1
2
3
4
5
6
7
8
9
10
11
(function ()
 {
   return (function ()
           {
             var _this = this;
             return (function ()
                     {
                       return _this + this;
                     });
           });
 })()

How will these improvements benefit the WebSharper™ ecosystem?

  • the output code of WebSharper™ projects will be leaner
  • macros will be a lot easier to write
  • the compiler will be smaller and simpler

In subsequent posts on the JavaScript optimization effort I will cover:

  • JavaScript Code Model (a form of CodeDOM for JavaScript)
  • Global and local tail call optimizations

Stay tuned!

By Anton Tayanovskyy on Monday, June 14, 2010 — 0 comments

WebSharper™: Towards Automated JavaScript BindingsCore team

This blog describes the pre-release WebSharper Extensibility Framework.

How would I call reasonably complex JavaScript functions from WebSharper? For an example, consider jQuery.ajax.

A first attempt would look like this:

1
2
[<Inline "jQuery.ajax($settings)">]
let ajax (settings: obj) : obj = null

This is hardly acceptable as it throws away all the information present on the documentation page and makes it the user's responsibility to figure out what exactly the ajax function expects. But spelling out the precise types requires a lot more work.

In practice, a big part of WebSharper codebase turns out to consist of stubs like these - classes and functions that instruct F# how to call a particular JavaScript API (think jQuery, Ext JS) and provide types for the API. The WebSharper JavaScript-binding code is repetitive, tedious to write and maintain and not straightforward to generate.

At IntelliFactory we have been exprimenting with several approaches to the problem, culminating in something we currently call the Extensibility Framework, or EF for short. The basic idea behind EF is that instead of writing the bindings by hand, we use an F#-embedded DSL to describe them.

jQuery.ajax with EF might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let private AjaxConfig =
    Pattern.Config "AjaxConfig" [] [
        "async" =~ T<bool>
        "beforeSend" =~ J.XMLHttpRequest ^-> T<unit>
        "cache" =~ T<bool>
        "complete" =~ J.XMLHttpRequest * T<string> ^-> T<unit>
        "contentType" =~ T<string>
        "context" =~ T<obj>
        // ..
    ]

    let private JQueryClass =
        Code.Class "JQuery"
        |=> JQuery
        |+> [
             "jQuery.ajax" => AjaxConfig ^-> T<unit>
             "jQuery.ajaxSetup" => AjaxConfig ^-> T<unit>
             "jQuery.contains" => 
                 J.Element?container * J.Node?contained ^-> T<bool>
        // ...

The use of the function would then look like this:

1
jQuery.Ajax(AjaxConfig(Async = false, ...))

The good news are several:

  • This is code-generating code - repetitive patterns can be abstracted over with plain functions in F#.
  • If a particular framework provides good documentation, this documentation can be parsed into EF values and then amended by merging it with hand-coded EF values where needed. Bindings generation is then semi-automatic.
  • Some common code-generating patterns will come with EF. Consider Pattern.Config above which generates a new configuration object class with the given required and optional fields.
  • Overload generation is automated. In EF, the type for a parameter that accepts either an int or a string can be spelled as T + T. The framework then figures out the correct overloads.

There is nothing particularly blog-worthy in the implementation of EF. It is mostly about figuring out the right interface (the most simple and yet diffuclt task there is). I will mention just one implementation detail I am particularly fond of. It is the use of F# operator overloading to describe method and function types. For example, these equalities are made to hold:

1
2
T<int -> int -> int> = T<int> ^-> T<int> ^-> T<int>
T<int * int -> int> = T<int> * T<int> ^-> T<int>
By Adam Granicz on Saturday, May 22, 2010 — 0 comments

WebSharper 2010 Standard is availableCore team

These are exciting times for the F# world! Monday, April 12, witnessed the launch of Visual Studio 2010 and the release of the official F# 2.0. Great job, F# team!

On our part, today we are pleased to announce the availability of WebSharper™ Platform 2010, version 1.0.

WebSharper™ is a platform for developing web applications in F# which includes:

  • A compiler from F# assemblies to JavaScript. WebSharper™ applications implement all client-side and server-side logic in F#, and run the client-side logic in JavaScript.
  • Support for nearly the entire F# language, many core F# libraries, and some .NET standard libraries in the JavaScript environment.
  • A custom RPC protocol for seamlessly communicating between the client and the server.
  • ASP.NET integration, with a way to package and deploy mixed client/server components, and manage their resource dependencies.
  • Visual Studio 2008 and 2010 integration with a WebSharper project template, build enhancements, and error location reporting.

The main highlights of this release are below.

Licensing

WebSharper™ 2010 Standard is available free of charge for both commercial and non-commercial purposes. We offer various support packages for individuals to large workgroups, and even entire enterprises, and premium extensions on our Purchase page. We also have a full range of training courses, consultation and expert services available. For more details, please send an email to sales@, or use our contact form.

The compiler

  • The error reporting has been much improved since the beta release. The compiler reports errors and warnings in bulk. Most messages carry source locations, allowing to click on them in Visual Studio.
  • The compilation of assemblies has been separated to avoid unnecessary recompilation, improving compilation time.
  • There are numerous improvements in the output code, to make it more compact, readable and efficient.

The standard library support

  • Support for Set<'T> and Map<'T1,'T2> with a backend based on AVL trees.
  • Support for System.DateTime and System.TimeSpan. Support for passing System.DateTime objects over RPC calls.

The language support

  • Thanks to the improvements in the recent F# compiler, constructors are no longer special-cased. Just like ordinary methods, they can now be marked with JavaScriptAttribute and implemented in F#.
  • More native JavaScript functionality is exposed for F# consumption, including such classes as JConsole, JDate, JObject (for JavaScript Console, Date and Object respectively).
  • Dom and jQuery bindings are likewise exposed for F#.

ASP.NET integration

  • WebSharper™ now integrates via an IHttpModule, detecting RPC call requests by a special header. This solution is robust to deploying WebSharper™ applications in arbitrary virtual folders.

The installer

  • Installation of templates for both Visual Studio 2008 and 2010, on 64 and 32-bit platforms.
  • Support for in-place upgrades and hotfix releases - the new versions of WebSharper™ 1.0 will be distributed as installers that will not require you to make any changes to your WebSharper™ projects in order to benefit from the latest versions' improvements.

We would love to hear from you! You can access a ton of information about WebSharper™, or its growing collection of extensions on the WebSharper™ home page.