Creating Domain Specific
       Languages in F#




          PhD student @ University of Cambridge
tomas@tomasp.net   Tomas Petricek          @tomaspetricek
         Conspirator behind http://fsharp.org
Real World Functional
                  Programming tutorials F# and C#
                  monads   functional concepts     practical examples




              industry experts F# Deep Dives
                                           .
  domain modeling      financial & insurance web & data
                  actor model   concurrency   social gaming



F# Trainings & Consulting
testing   London       async & concurrent   New York    DSLs
data processing    http://functional-programming.net
software stacks
       trainings teaching F# user groups     snippets

mac and linux   cross-platform books and tutorials
  F# Software Foundation
   F# community   open-source MonoDevelop
  http://www.fsharp.org
         contributions research support
                  consultancy mailing list
Domain-specific languages

We have a class of problems
 Create a language for the class
 Use language to solve them

DSLs and functional languages
 Internal DSLs are just library
 External DSLs are easier to build
Domain-specific languages

Language for solving specific problems

 Fun.cylinder
 |> Fun.translate (0, 0, 1)
 |> Fun.color Color.Gold $
 Fun.cone
 |> Fun.color Color.DarkRed


Contrast with general purpose languages
Demo: Building a castle

Domain Specific Language
 Defines a few simple primitives
 Extensible by composition

Single-purpose or general-purpose?
 Most code is single-purpose
 Can use general-purpose if needed

See also FAKE: the F# Make
Building a DSL for:
 Option Pricing
Demo: Modeling Euro options

What is the language?
 Primitive values
 Composition operations

How do we use the model?
 Drawing a pay-off diagram
 Calculating option price
 Checking for execution
Composed options
Building the model

Primitives of the language
    type OptionKind = Call | Put
    type Option =
      | European of OptionKind * float


Composition combinators
      | Combine of Option * Option
      | Times of float * Option
Demo: Building & using the
             DSL
Make it more convenient
  Custom operators
  Derived primitives

Use it for its purpose
  Drawing pay-off diagrams
  Evaluating option price
Domain-specific languages
Advantages                   Disadvantages
Readability                  Additional abstraction
  Greater for External DSL     Smaller for Internal DSL
Maintainability              Time to implement
  Hides the implementation     Easier for Internal DSL
  Internals can be changed   Time to learn
Domain Focus                   Avoid crazy operators
  Non-experts can read it      Make it familiar
Internal DSL: Building Blocks
Vanilla .NET           F# Specific
Method chaining        Pipelining
Enumerations           Discriminated Unions
Classes                Records
Operator Overloading   Custom Operators
Attributes             Quotations
Iterators & LINQ       Computation Expressions
Extension methods      Functions
Building a DSL for:
Detecting Price Patterns
Declining pattern
Rounding top pattern
Multiple bottom pattern
Doman-specific language approach

Primitive classifiers
  Declining price
  Rising price
Combinators for classifiers
  Average using regression
  Sequence multiple patterns
  Check patterns at the same time
Demo: Detecting price patterns
Building complex from simple
 Check multiple conditions
   let bothAnd a b =
     both a b |> map (fun (a, b) -> a && b)

 Calculate minimum value
   let minimum =
     reduce min |> map (fun v -> Math.Round(v, 2))

 All values are in a range
   let inRange min max =
     bothAnd (atLeast min) (atMost max)
How does it work?

What is a classifier?
   type Classifier<'T> =
     ClassifyFunc of ((DateTime * float)[] -> 'T)


A function value!
  Given data, calculate the result
  Generic – can produce any value
  Abstract – representation is hidden
Demo: Detecting more patterns

Double bottom pattern
  Change over regression
  Down–Up two times

Declining fast pattern
  Declining over regression
  (Max – Min) > 3 USD
Advanced Techniques
 for Embedded DSLs
Advanced Embedded DSLs
Computation expressions
  Reinterpret expression composition
  Add constructs with F# 3.0 queries

Meta-programming with quotations
  Reinterpret F# expressions

Active patterns
  More expressive pattern language
  Implementing external DSLs
Repeating patterns in DSLs

Repeating functions in DSLs
 Map: transform the produced value
   ('T -> 'R) -> Clsif<'T> -> Clsif<'R>
 Bind & return: composition of computations
   ('T -> Clsif<'R>) -> Clsif<'T> -> Clsif<'R>
   'T -> Clsif<'T>

Simplify using them? With language syntax?
F# computation expressions

Syntax for computations
  For types with certain operations
  Aka monads in Haskell

Declining fast pattern
  classify {
    let! max = P.maximum
    let! min = P.minimum
    let! upwards = P.regression P.rising
    return upwards & (abs (min - max) > 3.0) }
F# query expressions
Customize the meaning of a query
  event {
    for e in frm.MouseDown do
    pairwise into (e1, e2)
    select (e1.X - e2.X, e1.Y - e2.Y) into r
    iter (printfn "%A" r) }

Query for event processing
 Custom operators e.g. iter, select, pairwise
 Transformations, joins, merging and more
 Full power to be explored!
F# active patterns
Extending the pattern language
  match input with
  | Bracketed '*' '*' (body, rest)    -> (...)
  | Bracketed '[' ']' (body,
      Bracketed '(' ')' (link, rest)) -> (...)
  | _ -> (...)

Parsing Markdown format
 Detecting character patterns
 Detecting multi-line patterns
 See more at http://manning.com/petricek2
Summary
How To: Building your own DSL

    ❶ Understand Primitives
       and Combinators

   ❷ Model the language using
     Discriminated Unions

    ❸ Add convenient Syntax
For more information…
Learn and explore F#
 Read tutorials at http://tryfsharp.org

Join & help with F# Foundation
 Visit http://fsharp.org and for on GitHub!

New York F# Trainings & Tutorials in May
 Check out: http://functional-programming.net
 Contact me directly: tomas@tomasp.net

Creating Domain Specific Languages in F#

  • 1.
    Creating Domain Specific Languages in F# PhD student @ University of Cambridge tomas@tomasp.net Tomas Petricek @tomaspetricek Conspirator behind http://fsharp.org
  • 2.
    Real World Functional Programming tutorials F# and C# monads functional concepts practical examples industry experts F# Deep Dives . domain modeling financial & insurance web & data actor model concurrency social gaming F# Trainings & Consulting testing London async & concurrent New York DSLs data processing http://functional-programming.net
  • 3.
    software stacks trainings teaching F# user groups snippets mac and linux cross-platform books and tutorials F# Software Foundation F# community open-source MonoDevelop http://www.fsharp.org contributions research support consultancy mailing list
  • 4.
    Domain-specific languages We havea class of problems Create a language for the class Use language to solve them DSLs and functional languages Internal DSLs are just library External DSLs are easier to build
  • 5.
    Domain-specific languages Language forsolving specific problems Fun.cylinder |> Fun.translate (0, 0, 1) |> Fun.color Color.Gold $ Fun.cone |> Fun.color Color.DarkRed Contrast with general purpose languages
  • 6.
    Demo: Building acastle Domain Specific Language Defines a few simple primitives Extensible by composition Single-purpose or general-purpose? Most code is single-purpose Can use general-purpose if needed See also FAKE: the F# Make
  • 7.
    Building a DSLfor: Option Pricing
  • 8.
    Demo: Modeling Eurooptions What is the language? Primitive values Composition operations How do we use the model? Drawing a pay-off diagram Calculating option price Checking for execution
  • 9.
  • 10.
    Building the model Primitivesof the language type OptionKind = Call | Put type Option = | European of OptionKind * float Composition combinators | Combine of Option * Option | Times of float * Option
  • 11.
    Demo: Building &using the DSL Make it more convenient Custom operators Derived primitives Use it for its purpose Drawing pay-off diagrams Evaluating option price
  • 12.
    Domain-specific languages Advantages Disadvantages Readability Additional abstraction Greater for External DSL Smaller for Internal DSL Maintainability Time to implement Hides the implementation Easier for Internal DSL Internals can be changed Time to learn Domain Focus Avoid crazy operators Non-experts can read it Make it familiar
  • 13.
    Internal DSL: BuildingBlocks Vanilla .NET F# Specific Method chaining Pipelining Enumerations Discriminated Unions Classes Records Operator Overloading Custom Operators Attributes Quotations Iterators & LINQ Computation Expressions Extension methods Functions
  • 14.
    Building a DSLfor: Detecting Price Patterns
  • 15.
  • 16.
  • 17.
  • 18.
    Doman-specific language approach Primitiveclassifiers Declining price Rising price Combinators for classifiers Average using regression Sequence multiple patterns Check patterns at the same time
  • 19.
    Demo: Detecting pricepatterns Building complex from simple Check multiple conditions let bothAnd a b = both a b |> map (fun (a, b) -> a && b) Calculate minimum value let minimum = reduce min |> map (fun v -> Math.Round(v, 2)) All values are in a range let inRange min max = bothAnd (atLeast min) (atMost max)
  • 20.
    How does itwork? What is a classifier? type Classifier<'T> = ClassifyFunc of ((DateTime * float)[] -> 'T) A function value! Given data, calculate the result Generic – can produce any value Abstract – representation is hidden
  • 21.
    Demo: Detecting morepatterns Double bottom pattern Change over regression Down–Up two times Declining fast pattern Declining over regression (Max – Min) > 3 USD
  • 22.
  • 23.
    Advanced Embedded DSLs Computationexpressions Reinterpret expression composition Add constructs with F# 3.0 queries Meta-programming with quotations Reinterpret F# expressions Active patterns More expressive pattern language Implementing external DSLs
  • 24.
    Repeating patterns inDSLs Repeating functions in DSLs Map: transform the produced value ('T -> 'R) -> Clsif<'T> -> Clsif<'R> Bind & return: composition of computations ('T -> Clsif<'R>) -> Clsif<'T> -> Clsif<'R> 'T -> Clsif<'T> Simplify using them? With language syntax?
  • 25.
    F# computation expressions Syntaxfor computations For types with certain operations Aka monads in Haskell Declining fast pattern classify { let! max = P.maximum let! min = P.minimum let! upwards = P.regression P.rising return upwards & (abs (min - max) > 3.0) }
  • 26.
    F# query expressions Customizethe meaning of a query event { for e in frm.MouseDown do pairwise into (e1, e2) select (e1.X - e2.X, e1.Y - e2.Y) into r iter (printfn "%A" r) } Query for event processing Custom operators e.g. iter, select, pairwise Transformations, joins, merging and more Full power to be explored!
  • 27.
    F# active patterns Extendingthe pattern language match input with | Bracketed '*' '*' (body, rest) -> (...) | Bracketed '[' ']' (body, Bracketed '(' ')' (link, rest)) -> (...) | _ -> (...) Parsing Markdown format Detecting character patterns Detecting multi-line patterns See more at http://manning.com/petricek2
  • 28.
  • 29.
    How To: Buildingyour own DSL ❶ Understand Primitives and Combinators ❷ Model the language using Discriminated Unions ❸ Add convenient Syntax
  • 30.
    For more information… Learnand explore F# Read tutorials at http://tryfsharp.org Join & help with F# Foundation Visit http://fsharp.org and for on GitHub! New York F# Trainings & Tutorials in May Check out: http://functional-programming.net Contact me directly: tomas@tomasp.net

Editor's Notes

  • #13 Prefer internal DSLs