Download - Combinators, DSLs, HTML and F#
Combinators, DSLs, HTML and F#
Robert Pickering, ALTI
2
About the Presenter
Contact me:[email protected]://strangelights.com/blog
• Using F# for about 6 years• Oldest F# user outside of Microsoft• Written a book about F#
(now in its second edition)• Spend at least 2 years as a professional
functional programmer• I have 3 cats
What is a Combinator?
A combinator is a higher-order function that uses only function application and earlier
defined combinators to define a result from its arguments.
Source: Wikipedia, http://en.wikipedia.org/wiki/Combinatory_Logic
Combinatory Logic in Computing
In computer science, combinatory logic is used as a simplified model of computation, used in
computability theory and proof theory. Despite its simplicity, combinatory logic captures many
essential features of computation.
Source: Wikipedia, http://en.wikipedia.org/wiki/Combinatory_Logic
Combinator Library
"A combinator library offers functions (the combinators) that combine functions together to make
bigger functions"[1]. These kinds of libraries are particularly useful for allowing domain-specific
programming languages to be easily embedded into a general purpose language by defining a few primitive
functions for the given domain.
Souce: Wikipedia http://en.wikipedia.org/wiki/Combinator_library
[1] “A History of Haskell” Hudak, Hughes, Peyton Jones, Wadler
History of Haskell: Combinator Libraries
What is a combinator library? The reader will search in vain for a definition of this heavily used
term, but the key idea is this: a combinator library offers functions (the combinators) that
combine functions together to make bigger functions.
History of Haskell: Combinator Libraries
What is a combinator library? The reader will search in vain for a definition of this heavily
used term, but the key idea is this: a combinator library offers functions (the combinators) that
combine functions together to make bigger functions.
History of Haskell: Combinator Libraries
Another productive way to think of a combinator library is as a domain-specific language (DSL) for describing values of a
particular type.
What is a Domain Specific Language?
A programming language tailored for a particular application domain, which captures precisely the semantics of the application domain -- no more, no less.
A DSL allows one to develop software for a particular application domain quickly, and effectively, yielding programs that are easy to understand, reason about, and maintain.
Hudak
Combinators vs DSLs
• Combinartor libraries are a special case of DSLs– Sometimes called DSELs (Domain Specific Embed languages)
• DSELs have several advantages:― Inherit non-domain-specific parts of the design.― Inherit compilers and tools.― Uniform “look and feel” across many DSLs― DSLs integrated with full programming language, and with each other.
• DSELs one disadvantage:― Constrained by host language syntax and type system
What Makes F# a Suitable for DSLs ?
• Algebraic data types – type Option<'a> = Some x | None
• Lambda functions– fun x -> x + 1
• Define and redefine operators– let (++) x = x + 1
• Define custom numeric literals– let x : Expression = 1.0N
The Anatomy of a DSLtype Expression = | Add of Expression * Expression | Subtract of Expression * Expression | Multiply of Expression * Expression | Constant of int | Parameter of string with static member (+) (x, y) = Add(x, y) static member (-) (x, y) = Subtract(x, y) static member (*) (x, y) = Multiply(x, y)
module NumericLiteralN = let FromZero() = Constant 0 let FromOne() = Constant 1 let FromInt32 = Constant
let param = Parameter
Syntax Tree
Combinators
The Anatomy of a DSL
let expr = (1N + 2N) * (5N - 2N)
val expr : Expression = Multiply (Add (Constant 1,Constant 2), Subtract (Constant 5,Constant 2))
The Anatomy of a DSL
• Expressions now have an abstract tree like representation:
― Multiply― Add
― Constant 1― Constant 2
― Subtract― Constant 5― Constant 2
• This can then be evaluated• Or we can preform more advanced analysis
The Anatomy of a DSLlet evaluateExpression parameters = let rec innerEval tree = match tree with | Multiply (x, y) -> innerEval x * innerEval y | Add (x, y) -> innerEval x + innerEval y | Subtract (x, y) -> innerEval x - innerEval y | Constant value -> value | Parameter key -> Map.find key parameters innerEval
let expr = (1N + 2N) * (5N - 2N)
evaluateExpression Map.empty expr
The Anatomy of a DSL
The Anatomy of a DSLlet rec simplifyExpression exp = let simpIfPoss op exp1 exp2 = let exp' = op (simplifyExpression exp1, simplifyExpression exp2) if exp' = exp then exp' else simplifyExpression exp' match exp with | Multiply(Constant 0, Constant _) -> Constant 0 | Multiply(Constant _, Constant 0) -> Constant 0 | Multiply(Constant n1, Constant n2) -> Constant (n1 * n2) | Add(Constant n1, Constant n2) -> Constant (n1 + n2) | Subtract(Constant n1, Constant n2) -> Constant (n1 - n2) | Multiply(exp1, exp2) -> simpIfPoss Multiply exp1 exp2 | Add(exp1, exp2) -> simpIfPoss Add exp1 exp2 | Subtract(exp1, exp2) -> simpIfPoss Add exp1 exp2 | Constant _ | Parameter _ -> exp
The Anatomy of a DSL
Why a DSL for HTML?
<html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title></head><body> <h1>Hello world!</h1> <form id="form1"> <input type="text" name="name" /> </form></body></html>
Why a DSL for HTML ?
• HTML has a tree like structure
• We need be able to generate and manipulate this tree in an abstract, type safe way
Why a DSL for HTML?
― Tag: html― Tag: head
― Tag: title― Tag: body
― Tag: h1― Text: Hello world!
― Tag: form― Tag: input
― Attribute: type :: text― Attribute: name :: name
Why a DSL for HTML?
At this point any red blooded functional programmer should start foaming at the mouth,
yelling “build a combinator library”
Source: “Composing contracts: an adventure in financial engineering”Peyton Jones, Eber, Sewardhttp://research.microsoft.com/~simonpj/Papers/financial-contracts/contracts-icfp.htm
DSLs for Working with HTML
• #light – DSL for working with HTML, by Sadek Drobi: http://sharplight.codeplex.com/
• F# Web Tools – Tool kit for Ajax programing, by Tomáš Petříček: http://www.codeplex.com/fswebtools
• WebSharper – DSL for HTML with F# to JavaScript translator, by IntelliFactory: http://www.intellifactory.com/products/wsp
Hello world
[<JavaScript>] let Main () = let welcome = P [Text "Welcome"]
Div [ welcome Input [Type "Button"; Value "Click me!"] |> On Events.Click (fun e -> welcome.Text <- "Hello, world!") ]
Paragraph Element
Input Button Element
Client Side Event Handler
How Does it Work?
• At compile time an extra step takes place:– Functions & types are translated into JavaScript– Compiler attempts to optimize JavaScript code– Compiler tries to preserve binding names
• F# functions are compiled using the F# quotations system
Aside: Quotations in F#open Microsoft.FSharp.Quotations.Patternsopen Microsoft.FSharp.Quotations.DerivedPatterns
let quotation = <@ 1 + 1 @>
// a function to interpret very simple quotationslet rec interpretQuotation exp = match exp with | Value (x, typ) when typ = typeof<int> -> printfn "%d" (x :?> int) | SpecificCall <@ (+) @> (_, _, [l;r]) -> interpretQuotation l printfn "+" interpretQuotation r | _ -> printfn "not supported" // test the functioninterpretQuotation quotation
Formlets – Compositional Forms
[<JavaScript>] let input label err = Controls.Input "" |> Validator.IsNotEmpty err |> Controls.Enhance.WithLabel label
[<JavaScript>] let inputInt label err = Controls.Input "" |> Validator.IsInt err |> Controls.Enhance.WithLabel label
Text Input Element
Add Validation Element
Add Label Element
Formlets – Compositional Forms
[<JavaScriptType>] type BasicInfo = { Name : string; Age : int }
[<JavaScript>] let BasicInfoForm () : Formlet<BasicInfo> = Formlet.Yield (fun name age -> { Name = name; Age = age |> int }) <*> input "Name" "Please enter your name" <*> inputInt "Age" "Please enter a valid age"
Construct form result
Construct and compose input
elements
Formlets – Compositional Forms
let conf = { Render.FormConfiguration.Default with Header = "Sign up" } Render.FormThenResponse conf (ContactForms.BasicInfoForm()) (fun info -> Div [ P [ "Thanks " + info.Name ] P [ "You are " + string info.Age + " years old" ] ])
Configuration options
Function that constructs result
Form and config
Plotting Graphs Client SideDemo
Flowlets – Composing Formlets
Flowlet.Flowlet.Do { let! info = ContactForms.BasicInfoForm() |> Flowlet.OfFormlet conf1 let! contact = ContactForms.ContactInfoForm() |> Flowlet.OfFormlet conf2 return info, contact }
Flowlets – Composing FormletsFlowlet.Run (fun (info, contact) -> let result = match contact with | ContactForms.ContactVia.Address address -> "the address: " + address.Street + ", " + address.City + ", " + address.Country | ContactForms.ContactVia.Phone phone -> "the phone number: " + phone let results = FieldSet [ Legend [Text "Sign-up summary"] P ["Hi " + info.Name + "!" |> Text] P ["You are " + string info.Age + " years old" |> Text] P ["Your preferred contact method is via " + result |> Text] ] steps -< [ results ] |> ignore)
Wrapping It Up
• Combinator libraries/DSL are an excellent way of tackling many problems– Especially if that problem involves some kind of
tree manipulation
• F# provides the features you need to implement combinator libraries
MSDN Center: http://msdn.microsoft.com/fsharp/
User’s forums:http://cs.hubfs.net/forumshttp://stackoverflow.com/tags/F%23
Blogs (there are lots of others) : http://blogs.msnd.com/dsymehttp://strangelights.com/blog
Websites :http://code.msdn.microsoft.com/fsharpsampleshttp://code.google.com/hosting/search?q=label:fsharphttp://codeplex.com/Project/ProjectDirectory.aspx?TagName=F%23
Further F# Info
Books