F# Quotations:
“Code as Data”
Jack Pappas
Dmitry Morozov
SkillsMatter Progressive F# Tutorials NYC
September 19th, 2013
Code as Data
• Code & Data – What is the difference?
• Is there a difference?
• Programs exist to process data
– The F# co...
This Session
• What is a “quoted expression”?
– A simple, immutable data structure
– Represents a fragment of F# code
• Sy...
Background
• The idea of treating code as data first
appeared in Lisp
Lisp F#
Code (1 2 3) [1; 2; 3]
Code as Data ‘(1 2 3)...
Background
• A language that has the natural ability to
manipulate itself is extremely powerful
• “Amplify” a developer’s ...
Background
• Other languages can manipulate their own
code
– clang: C++ program, manipulates C++
– Roslyn: C# library, man...
Background
• Now that we can manipulate code as data,
what can we do with it?
• Transform
– modify, convert, translate
• A...
Background
• Execute
– Interpret the code/data
– Translate to another lang., compile, execute
– Specialized hardware (e.g....
Use Cases
• LINQ support in F#
– Extension of this idea:
Cheney, Lindley, Wadler.
“The essence of language-integrated quer...
Use Cases
• Testing
– Moq/Foq/Unquote
• GPU programming
– Compute: FSCL, QuantAlea
– Graphics: SharpShaders (F# -> HLSL)
•...
Comparing Alternatives
• What alternatives exist to quotations?
– F# AST
– LINQ Expression Trees
– CIL (MSIL)
• Imperative...
Comparing Alternatives
• F# AST
– Designed for the compiler’s internal use
– Carries more information than quotations
– Re...
Comparing Alternatives
• LINQ Expression Trees
– Introduced in .NET 3.5; initially somewhat limited
– Expanded in .NET 4.0...
Comparing Alternatives
• Common Intermediate Language (CIL)
– Low-level; relatively difficult to work with
– Supports all ...
Quotations: How-To
• Open some namespaces
• Define a module, then some functions within
the module
open System.Reflection
...
Quotations: How-To
• Apply [<ReflectedDefinition>] to your function
– Or, apply it to your module as a shortcut for applyi...
Quotations: How-To
• Using Reflection, get the MethodInfo for your
function
• Call Expr.TryGetReflectedDefinition with the...
Quotations: How-To
[<EntryPoint>]
let main argv =
let fooType = typeof<Foo.Dummy>.DeclaringType
let addTwoMethodInfo =
mat...
Quotations: How-To
• For each active pattern in Quotations.Patterns,
there is a corresponding static member of the
Expr ty...
Quotations: How-To
• Expr<‘T> is just a wrapper around Expr
– Use the .Raw property for Expr<‘T> -> Expr
– Use the Coerce ...
Quotations: How-To
• “Splicing” – a way to combine quotations
– Inserts one quotation into another
– Typed:
let bar = <@ 3...
Quotations: How-To
• Note: You don’t always need
[<ReflectedDefinition>] to use quotations
• Using our previous example, t...
Computations on Trees
• When working with Quotations, it’s critical
you’re comfortable with trees and recursion
• Tree com...
Computations on Trees
• Possible to implement a functional alternative
to the “visitor” pattern?
• Knuth did – decades ago...
Computations on Trees
• Attribute grammars are declarative
– They do not define any traversal order
• Attribute grammars a...
Computations on Trees
• Three main kinds of attributes
• Inherited (L-attributes)
– Attribute “inherited” from parent node...
Computations on Trees
• Threaded (SL-attributes)
– Attribute value inherited from parent node,
modified by child, then pas...
Exercises
• Implement a function(s) which, given an Expr:
– Print the equiv. F# source code
– Invert the mathematical oper...
Upcoming SlideShare
Loading in …5
×

Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations code as-data for f#

1,166 views
956 views

Published on

Code Quotations: Code-as-Data for F#
This tutorial will cover F# Code Quotations in-depth. You'll learn what Code Quotations are, how to use them, and where to apply them in your applications. We'll work through several real-world examples to highlight the important features -- and potential pitfalls -- of Code Quotations.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,166
On SlideShare
0
From Embeds
0
Number of Embeds
58
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations code as-data for f#

  1. 1. F# Quotations: “Code as Data” Jack Pappas Dmitry Morozov SkillsMatter Progressive F# Tutorials NYC September 19th, 2013
  2. 2. Code as Data • Code & Data – What is the difference? • Is there a difference? • Programs exist to process data – The F# compiler processes data (your source code) • Source code is no different than other kinds of data
  3. 3. This Session • What is a “quoted expression”? – A simple, immutable data structure – Represents a fragment of F# code • Syllabus – Background – Working with Quotations – Manipulating Quotations – Applications of Quotations
  4. 4. Background • The idea of treating code as data first appeared in Lisp Lisp F# Code (1 2 3) [1; 2; 3] Code as Data ‘(1 2 3) <@ [1; 2; 3] @>
  5. 5. Background • A language that has the natural ability to manipulate itself is extremely powerful • “Amplify” a developer’s productivity using metaprogramming techniques
  6. 6. Background • Other languages can manipulate their own code – clang: C++ program, manipulates C++ – Roslyn: C# library, manipulates C# – f2c: C program, manipulates FORTRAN and C • What makes Lisp and F# different? – Reflective meta-programming – Built-in language feature vs. external functionality
  7. 7. Background • Now that we can manipulate code as data, what can we do with it? • Transform – modify, convert, translate • Analyze – Static analysis – Advanced testing techniques (e.g., verification) – Collect and record code metrics (e.g., complexity)
  8. 8. Background • Execute – Interpret the code/data – Translate to another lang., compile, execute – Specialized hardware (e.g., GPU, FPGA) – Specialized execution (e.g., auto-parallelization) – Execute remotely (e.g., web service) – Some combination of the above – (Rarely) execute in same context, e.g., by translating to IL and executing
  9. 9. Use Cases • LINQ support in F# – Extension of this idea: Cheney, Lindley, Wadler. “The essence of language-integrated query” • Use as an IL when developing type providers – Quotations much easier to work with – Create quotations, translate to IL
  10. 10. Use Cases • Testing – Moq/Foq/Unquote • GPU programming – Compute: FSCL, QuantAlea – Graphics: SharpShaders (F# -> HLSL) • Web Development (F# -> JavaScript) – WebSharper – FunScript – PitFw
  11. 11. Comparing Alternatives • What alternatives exist to quotations? – F# AST – LINQ Expression Trees – CIL (MSIL) • Imperative: Expression Trees, CIL – C# lambdas compiled into Expression Trees by the C# compiler • Functional: F# AST, Quotations
  12. 12. Comparing Alternatives • F# AST – Designed for the compiler’s internal use – Carries more information than quotations – Requires additional library – Unwieldy for simple use cases
  13. 13. Comparing Alternatives • LINQ Expression Trees – Introduced in .NET 3.5; initially somewhat limited – Expanded in .NET 4.0; now roughly 1:1 with CIL – Doesn’t support certain functional features like closures
  14. 14. Comparing Alternatives • Common Intermediate Language (CIL) – Low-level; relatively difficult to work with – Supports all CLR features – F# Quotations don’t support all CLR features ● Notably, throw and rethrow – these need to be wrapped in a function and compiled using the proto compiler ● No fault/filter clauses • F# Quotations don’t support open generics
  15. 15. Quotations: How-To • Open some namespaces • Define a module, then some functions within the module open System.Reflection open Microsoft.FSharp.Reflection open Microsoft.FSharp.Quotations module Foo = let addTwo x = x + 2
  16. 16. Quotations: How-To • Apply [<ReflectedDefinition>] to your function – Or, apply it to your module as a shortcut for applying it to all functions in the module module Foo = /// Dummy class used to retrieve /// the module type. type internal Dummy = class end [<ReflectedDefinition>] let addTwo x = x + 2
  17. 17. Quotations: How-To • Using Reflection, get the MethodInfo for your function • Call Expr.TryGetReflectedDefinition with the MethodInfo to get the Expr for the method
  18. 18. Quotations: How-To [<EntryPoint>] let main argv = let fooType = typeof<Foo.Dummy>.DeclaringType let addTwoMethodInfo = match fooType.GetMethod "addTwo" with | null -> None | x -> Some x addTwoMethodInfo |> Option.map Expr.TryGetReflectedDefinition |> Option.iter (printfn "addTwo: %A")
  19. 19. Quotations: How-To • For each active pattern in Quotations.Patterns, there is a corresponding static member of the Expr type. – These are used to construct and destructure each quotation “case”. • Two types of quotations: typed and untyped – Typed: Expr<‘T> – Untyped: Expr
  20. 20. Quotations: How-To • Expr<‘T> is just a wrapper around Expr – Use the .Raw property for Expr<‘T> -> Expr – Use the Coerce pattern for Expr -> Expr<‘T> • Quoting an expression – Typed: <@ fun x -> x + 2 @> – Untyped: <@@ fun x -> x + 2 @@>
  21. 21. Quotations: How-To • “Splicing” – a way to combine quotations – Inserts one quotation into another – Typed: let bar = <@ 3 + "Blah".Length @> let foo = <@ fun x -> x + %bar @> – Untyped: let bar = <@@ 3 + "Blah".Length @@> let foo = <@@ fun x -> x + %%bar @@>
  22. 22. Quotations: How-To • Note: You don’t always need [<ReflectedDefinition>] to use quotations • Using our previous example, this is equivalent let addTwo = <@ fun x -> x + 2 @>
  23. 23. Computations on Trees • When working with Quotations, it’s critical you’re comfortable with trees and recursion • Tree computations in imperative languages usually built around the “visitor” pattern – Visitor class usually holds private, mutable state – Often implemented as an abstract base class per tree type, and one virtual method per node type – Mechanics of the traversal intermixed with computation happening at nodes
  24. 24. Computations on Trees • Possible to implement a functional alternative to the “visitor” pattern? • Knuth did – decades ago! • Introducing “attribute grammars” – Initially used as a means of describing how LL/LR parsers annotate a parse tree – Later, used to describe how “attributes” are computed from on tree
  25. 25. Computations on Trees • Attribute grammars are declarative – They do not define any traversal order • Attribute grammars allow you to define purely functional, monadic computations over trees – For those familiar with Haskell – attribute evaluation is actually co-monadic • AGs on ASTs (or Quotations) can be used to implement purely functional AOP
  26. 26. Computations on Trees • Three main kinds of attributes • Inherited (L-attributes) – Attribute “inherited” from parent node – Compare to the reader workflow • Synthesized (S-attributes) – Attribute “synthesized” by a child node, passed back up to parent node – Compare to the writer workflow
  27. 27. Computations on Trees • Threaded (SL-attributes) – Attribute value inherited from parent node, modified by child, then passed back up to parent – Combination of Inherited and Synthesized – Compare to the state workflow • Attribute values can be int, string, UDTs, etc. • They can also be tree nodes – We can use this to define tree transformations
  28. 28. Exercises • Implement a function(s) which, given an Expr: – Print the equiv. F# source code – Invert the mathematical operators (+)/(-), (*)/(/) – Compute the set of methods called by the Expr ● Bonus: Compute this transitively – Determine if the Expr can ever raise an exn – Determine if the Expr is pure (side-effect free) – Rewrite it so all strings are passed through String.Intern

×