<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dave Thomas</title>
    <description>The latest articles on DEV Community by Dave Thomas (@7sharp9).</description>
    <link>https://dev.to/7sharp9</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F243315%2Fdc80986d-93cb-4d45-a2b3-8d1e7c8a8bea.jpeg</url>
      <title>DEV Community: Dave Thomas</title>
      <link>https://dev.to/7sharp9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/7sharp9"/>
    <language>en</language>
    <item>
      <title>An Introduction to Myriad</title>
      <dc:creator>Dave Thomas</dc:creator>
      <pubDate>Tue, 04 Feb 2020 13:12:55 +0000</pubDate>
      <link>https://dev.to/7sharp9/an-introduction-to-myriad-1ald</link>
      <guid>https://dev.to/7sharp9/an-introduction-to-myriad-1ald</guid>
      <description>&lt;p&gt;I released a new meta programming club &lt;a href="https://youtu.be/Yef8EJJfd9Q"&gt;video&lt;/a&gt; a while back on my YouTube &lt;a href="https://www.youtube.com/channel/UC0kXc1f_WBYSklrElcPWzgg"&gt;channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Yef8EJJfd9Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;But I thought I would write a little about it here too, this is a mirror of the post on my &lt;a href="https://7sharp9.dev/2019/11/06/2019-11-06-myriad-intro/"&gt;website&lt;/a&gt; but I like the community and sharing aspect of posts here on &lt;a href="https://dev.to/"&gt;dev.to&lt;/a&gt; so here is is :-)&lt;/p&gt;

&lt;p&gt;I recently did a little work to flesh out the plugin interface for Myriad.  My friend &lt;a href="https://twitter.com/enricosada"&gt;Enrico Sada&lt;/a&gt; helped out with &lt;br&gt;
some of the fiddly MsBuild work in dotnet which can be a little confusing at times.  &lt;/p&gt;

&lt;p&gt;The gist of the plugin is that you must implement the following interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;IMyriadGenerator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;namespace'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;ParsedInput&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;SynModuleOrNamespaceRcd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And annotate you type with the &lt;code&gt;MyriadGeneratorAttribute&lt;/code&gt; specifying the name of your plugin so that it can be found.&lt;br&gt;&lt;br&gt;
Heres an example plugin from the &lt;a href="https://github.com/MoiraeSoftware/myriad"&gt;Myriad repo&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyriadGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"example1"&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Example1Gen&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IMyriadGenerator&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;let42&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                &lt;span class="nn"&gt;SynModuleDecl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLet&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;SynBindingRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Let&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
                            &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLongIdent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;LongIdentWithDots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateString&lt;/span&gt; &lt;span class="s2"&gt;"fourtyTwo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nc"&gt;Expr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynExpr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateConst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;SynConst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;componentInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynComponentInfoRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nn"&gt;Ident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="s2"&gt;"example1"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;nestedModule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynModuleDecl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateNestedModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;componentInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;let42&lt;/span&gt; &lt;span class="o"&gt;])&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;namespaceOrModule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;SynModuleOrNamespaceRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLong&lt;/span&gt; &lt;span class="n"&gt;namespace'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Declarations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;nestedModule&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;namespaceOrModule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All this example does is generate a simple module like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="n"&gt;example1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fourtyTwo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ast Helping Hand
&lt;/h3&gt;

&lt;p&gt;Unfortunately working with the AST can be quite verbose in Myriad I use &lt;a href="https://github.com/ctaggart/FsAst"&gt;FsAst&lt;/a&gt; which uses the record update syntax to aid&lt;br&gt;
in the construction of AST nodes by using the record update syntax so you don't have to supply every parameter.  &lt;/p&gt;

&lt;p&gt;Take a Let binding AST element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nn"&gt;SynBindingRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Let&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;
    &lt;span class="nc"&gt;Expr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we did not use the record update syntax in &lt;code&gt;SynBindingRcd&lt;/code&gt; then we would have to supply every parameter for the let binding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Access&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;
    &lt;span class="nc"&gt;Kind&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynBindingKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NormalBinding&lt;/span&gt;
    &lt;span class="nc"&gt;IsInline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;
    &lt;span class="nc"&gt;IsMutable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;
    &lt;span class="nc"&gt;Attributes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynAttributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Empty&lt;/span&gt;
    &lt;span class="nc"&gt;XmlDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;PreXmlDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Empty&lt;/span&gt;
    &lt;span class="nc"&gt;ValData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SynValData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="nn"&gt;MemberFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InstanceMember&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;SynValInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;
    &lt;span class="nc"&gt;ReturnInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;
    &lt;span class="nc"&gt;Expr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt;
    &lt;span class="nc"&gt;Range&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Zero&lt;/span&gt;
    &lt;span class="nc"&gt;Bind&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SequencePointInfoForBinding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NoSequencePointAtInvisibleBinding&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is not exactly fun, the record update syntax makes these type of things easy to define and compose together.&lt;/p&gt;




&lt;p&gt;The new version of Myriad can be found on Nuget &lt;a href="https://www.nuget.org/packages/Myriad.Sdk/0.2.4"&gt;here&lt;/a&gt; or at its &lt;a href="https://github.com/MoiraeSoftware/myriad"&gt;repo&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;I hope you enjoyed the video and this brief post!&lt;/p&gt;

&lt;p&gt;Until next time!  &lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>metaprogramming</category>
      <category>functional</category>
    </item>
    <item>
      <title>Applied Meta-Programming In F# With Myriad And Falanx</title>
      <dc:creator>Dave Thomas</dc:creator>
      <pubDate>Sat, 01 Feb 2020 12:17:49 +0000</pubDate>
      <link>https://dev.to/7sharp9/applied-meta-programming-with-myriad-and-falanx-7l4</link>
      <guid>https://dev.to/7sharp9/applied-meta-programming-with-myriad-and-falanx-7l4</guid>
      <description>&lt;h2&gt;
  
  
  What is Myriad?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; is a pre-compilation tool that generates code from code.  It is integrated into the project build cycle via an MSBuild extension.  It is also possible to invoke the tool separately as a &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/?tabs=netcore2x"&gt;CLI tool&lt;/a&gt; but this essay will deal with describing the integration within an MSBuild project as this would be the most common pattern of usage.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Historical basis
&lt;/h2&gt;

&lt;p&gt;Before I dig into the detail its best to get some historical details as the &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; project stems from previous meta-programming work that I have been doing over the last year, perhaps also further back through my history of using F# too.  The &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; project built the first steps towards &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; by taking blocks of functionality from different areas of the F# ecosystem and welding them together to aid in code generation.  Lets go through some of the different way you can utilise meta-programming in F#.    &lt;/p&gt;

&lt;h2&gt;
  
  
  Meta-programming 101
&lt;/h2&gt;

&lt;p&gt;F# has a number of meta-programming facilities that I have spoke about before in my previous blog posts:  &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Code Quotations&lt;/a&gt;, &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt;, &lt;a href="https://fsharp.github.io/FSharp.Compiler.Service/typedtree.html"&gt;Typed Expressions&lt;/a&gt;, and also the &lt;a href="https://fsharp.github.io/FSharp.Compiler.Service/untypedtree.html"&gt;untyped abstract syntax tree - AST&lt;/a&gt;.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Quotations
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt; are backed by reflection and mainly used to transform F# to another language.  They are limited in that they do not represent the whole F# language.  Types and modules are not able to be represented like they are in the F# AST.  They also do not encode F# on a one to one basis in terms of representing F# expressions.  Some elements like discriminated union decomposition, pattern matching and function fixity are not represented in the same form as they occur in F#, details are lost in transformation.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Type Providers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; use &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt; to encode method information and use these expression with a skeleton of types produced by some for of schema or input.  &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; can be useful in some limited scenarios.  Building a &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Provider&lt;/a&gt; should not be taken lightly as there can often be a lot of edge cases and debugging before they are production ready.  There's also the fact that &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; can not create any F# constructs like &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;records&lt;/a&gt; or &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;Discriminated Unions&lt;/a&gt;.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Typed Expressions
&lt;/h3&gt;

&lt;p&gt;Typed expressions are used for whole language or system transformations and is the technique used in &lt;a href="https://7sharp9.github.io/2015/07/12/2015-07-08-meta-matic/"&gt;Fable&lt;/a&gt; to transpile F# to JavaScript.  You can read more about typed expressions in my &lt;a href="https://7sharp9.github.io/2015/07/12/2015-07-08-meta-matic/"&gt;Metamatic blog post&lt;/a&gt;.  They have no dependency on reflection and do not require any on disk assemblies.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Untyped AST
&lt;/h3&gt;

&lt;p&gt;The untyped AST or AST for short is not an area that has been widely used, mainly as working with the AST is quite tricky outside of the compiler and the AST is normally produced by the compiler as a result of the parsing phase.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Falanx Whistle-stop Tour
&lt;/h2&gt;

&lt;p&gt;It is not the scope of this essay to describe &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; in detail but reading some of the background on it may provide an insight on how the direction in &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; was formed and how some of the technical challenges experienced in &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; drove the resulting design decisions.  The following is a quick run through some of the core concepts and issues faced in &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; uses a mixture of &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt;, &lt;em&gt;(mainly the &lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;Type Provider SDK&lt;/a&gt; not the actual Type Provider invocation mechanism)&lt;/em&gt; &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt;, and AST manipulation to generate source code.  &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; evolved from a minimum viable product where the key input factors were a prototype which could be developed within a few weeks that could take a &lt;a href="https://developers.google.com/protocol-buffers/"&gt;protocol buffer&lt;/a&gt; schema and generate F# &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;records&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;Discriminated Union&lt;/a&gt; types as output.  &lt;/p&gt;

&lt;p&gt;This is an example of a &lt;a href="https://developers.google.com/protocol-buffers/"&gt;Protocol Buffer&lt;/a&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="n"&gt;syntax&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;BundleRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="n"&gt;martId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;member_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Falanx works by defining an MSBuild extension that references a &lt;a href="https://developers.google.com/protocol-buffers/"&gt;Protocol Buffer&lt;/a&gt; file and generates another file in response to it containing F# &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;records&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;discriminated unions&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Falanx.Sdk"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"0.4.*"&lt;/span&gt; &lt;span class="na"&gt;PrivateAssets=&lt;/span&gt;&lt;span class="s"&gt;"All"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ProtoFile&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"..\proto\bundle.proto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputPath&amp;gt;&lt;/span&gt;mycustom.fs&lt;span class="nt"&gt;&amp;lt;/OutputPath&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ProtoFile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;ProtoFile Include="..\proto\bundle.proto"&amp;gt;&lt;/code&gt; is the input file and &lt;code&gt;&amp;lt;OutputPath&amp;gt;mycustom.fs&amp;lt;/OutputPath&amp;gt;&lt;/code&gt; is the output file.  &lt;/p&gt;

&lt;p&gt;The resulting generated source code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CLIMutable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;BundleRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;martId&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;
      &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;memberId&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;JsonObjCodec&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;martId&lt;/span&gt; &lt;span class="n"&gt;memberId&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;martId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;martId&lt;/span&gt;
          &lt;span class="n"&gt;memberId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memberId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;!&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Operators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jopt&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"martId"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;martId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Operators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jopt&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"memberId"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memberId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ZeroCopyBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;writeOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writeInt32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;martId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;writeOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writeString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memberId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ZeroCopyBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IMessage&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ZeroCopyBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="nn"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ZeroCopyBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;enumerator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                &lt;span class="nn"&gt;ZeroCopyBuffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;GetEnumerator&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;enumerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MoveNext&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enumerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Current&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FieldNum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memberId&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readString&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FieldNum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;martId&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readInt32&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;enumerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dispose&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SerializedLength&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializedLength&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first part of the generated code is a &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;record&lt;/a&gt; definition followed by binary and json serialization methods.  &lt;code&gt;JsonObjCodec&lt;/code&gt; is used via the &lt;a href="https://github.com/mausch/Fleece"&gt;Fleece&lt;/a&gt; library, &lt;code&gt;Serialize&lt;/code&gt; and &lt;code&gt;Deserialize&lt;/code&gt; are used by the Froto&lt;a href="https://github.com/ctaggart/froto"&gt;12&lt;/a&gt; library.  The &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;records&lt;/a&gt; produced support both binary and json serialization via the &lt;a href="https://github.com/ctaggart/froto"&gt;Froto&lt;/a&gt; and &lt;a href="https://github.com/mausch/Fleece"&gt;Fleece&lt;/a&gt; libraries respectively.  &lt;a href="https://github.com/mausch/Fleece"&gt;Fleece&lt;/a&gt; ss interesting in that the generated code uses applicative style and only requires a codec property &lt;code&gt;JsonObjCodec&lt;/code&gt; to serialize and deserialize to json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//serialize&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bundleRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;memberId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="s2"&gt;"172c"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toJson&lt;/span&gt; &lt;span class="n"&gt;bundleRequest&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;//deserialize&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bundleRequest2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseJson&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BundleRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"""{"&lt;/span&gt;&lt;span class="n"&gt;martId&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;memberId&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="s2"&gt;"}"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Parsing/AST
&lt;/h4&gt;

&lt;p&gt;Part of the technical challenge of &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; was the time pressure to build a minimum viable product in a short amount of time.  &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; were out of the question as one of the main requirements were to produce F# &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;records&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;Discriminated Unions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/ctaggart/froto"&gt;Froto&lt;/a&gt; library already had a working &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Provider&lt;/a&gt; but the resulting output code was not F# &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;records&lt;/a&gt; and [Discriminated Unions&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;22&lt;/a&gt; as &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; only support basic CLR types no F# specific types are supported.  Another issue was that &lt;a href="https://developers.google.com/protocol-buffers/"&gt;Protocol Buffers&lt;/a&gt; version 2 was the only version supported, so we decided to use the parser from &lt;a href="https://github.com/ctaggart/froto"&gt;Froto&lt;/a&gt; and make a PR to update it to support Protocol Buffers 3 syntax.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Quotations
&lt;/h4&gt;

&lt;p&gt;We now have the Protocol Buffer 3 file represented as an abstract syntax tree.  In &lt;a href="https://github.com/ctaggart/froto"&gt;Froto&lt;/a&gt; there also exist &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; that were used for the Provided Type methods that were used in the &lt;a href="https://github.com/ctaggart/froto"&gt;Froto&lt;/a&gt; &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Provider&lt;/a&gt;, although we were not using the [Type Provider&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;9&lt;/a&gt; in &lt;a href="https://github.com/ctaggart/froto"&gt;Froto&lt;/a&gt;, we could reuse some of these &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; and adapt them for our needs.  Extra &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; were also created to form the &lt;code&gt;JsonObjCodec&lt;/code&gt; property from the code above.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Quotations -&amp;gt; AST
&lt;/h4&gt;

&lt;p&gt;The next part was to take the &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; representing &lt;code&gt;Serialize&lt;/code&gt;, &lt;code&gt;Deserialize&lt;/code&gt; and &lt;code&gt;JsonObjCodec&lt;/code&gt; and convert them to source code.  Both quotations and the F# AST represent similar but not quite the same things:  A collection of nodes that represent the abstract notion of code.  &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt; do not map fully into the F# AST as they only represent a subset of the AST, types for example are not present in &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt;, neither can quotation map functions like for like into F# AST nodes as &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; lack detail compared the the F# AST, such as fixity information, pattern matching and decomposition of Discriminated Unions are all altered in the quotation of literals or composing of Quotation Expressions.  &lt;/p&gt;

&lt;p&gt;Theres an interesting library called &lt;a href="https://github.com/eiriktsarpalis/QuotationCompiler"&gt;Quotation Compiler&lt;/a&gt; by &lt;a href="https://github.com/eiriktsarpalis"&gt;Eirik Tsarpalis&lt;/a&gt;, inside this library there a piece of code which uses an entry point into the F# compiler that allows you to compile an AST to a dll rather than using a source file.  I remember looking through this previously and wondered if something similar could be used.  I also found that there was a function that transformed &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; to fragments of an AST too.  I found that this could be adapted to what I needed with some simple changes.  Unfortunately it was not possible to reference this library directly as in the end I needed to heavily modify it to work with the &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; that referenced Provided types due to reflection issues, but it did form the basis for the bulk of the solution.  The reflection issue it to do with the way &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; are represented.  Each type produced in a generative type provider is backed by a subtype of one of the reflection base types: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Base&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedTypeSymbol&lt;/td&gt;
&lt;td&gt;TypeDelegator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedSymbolMethod&lt;/td&gt;
&lt;td&gt;MethodInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedStaticParameter&lt;/td&gt;
&lt;td&gt;ParameterInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedParameter&lt;/td&gt;
&lt;td&gt;ParameterInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedConstructor&lt;/td&gt;
&lt;td&gt;ConstructorInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedMethod&lt;/td&gt;
&lt;td&gt;MethodInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedProperty&lt;/td&gt;
&lt;td&gt;PropertyInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedEvent&lt;/td&gt;
&lt;td&gt;EventInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedField&lt;/td&gt;
&lt;td&gt;FieldInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedTypeDefinition&lt;/td&gt;
&lt;td&gt;TypeDelegator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MethodSymbol2&lt;/td&gt;
&lt;td&gt;MethodInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConstructorSymbol&lt;/td&gt;
&lt;td&gt;ConstructorInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MethodSymbol&lt;/td&gt;
&lt;td&gt;MethodInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PropertySymbol&lt;/td&gt;
&lt;td&gt;PropertyInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventSymbol&lt;/td&gt;
&lt;td&gt;EventInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FieldSymbol&lt;/td&gt;
&lt;td&gt;FieldInfo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type Symbol&lt;/td&gt;
&lt;td&gt;TypeDelegator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TargetGenericParam&lt;/td&gt;
&lt;td&gt;TypeDelegator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TargetTypeDefinition&lt;/td&gt;
&lt;td&gt;TypeDelegator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TargetModule&lt;/td&gt;
&lt;td&gt;Module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TargetAssembly&lt;/td&gt;
&lt;td&gt;Assembly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProvidedAssembly&lt;/td&gt;
&lt;td&gt;Assembly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These can start to become an issue when you start to use reflection on the Provided Types as the &lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;Type Provider SDK&lt;/a&gt; only implements the minimal overloads from the base types so you can quickly encounter not implemented exceptions quite easily.  An example of this is if you tried to access the &lt;code&gt;ReflectedType&lt;/code&gt; property of a &lt;code&gt;ProvidedProperty&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;notRequired&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;opname&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"The operation '%s' on item '%s' should not be called on provided type, member or parameter of type '%O'. Stack trace:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;%s"&lt;/span&gt; &lt;span class="n"&gt;opname&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetType&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nn"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StackTrace&lt;/span&gt;
        &lt;span class="nn"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NotSupportedException&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;ProvidedProperty&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;inherit&lt;/span&gt; &lt;span class="nc"&gt;PropertyInfo&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReflectedType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notRequired&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="s2"&gt;"ReflectedType"&lt;/span&gt; &lt;span class="n"&gt;propertyName&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ended up requiring some creative workarounds and reverse engineering of the reflection functionality in FSharp.Core which was quite time consuming.  An example of this when converting a &lt;code&gt;NewRecord&lt;/code&gt; quotation expression inot an aST fragment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;NewRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;synTy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sysTypeToSynType&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt; &lt;span class="n"&gt;knownNamespaces&lt;/span&gt; &lt;span class="n"&gt;ommitEnclosingType&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="o"&gt;:?&lt;/span&gt; &lt;span class="nc"&gt;ProvidedRecord&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RecordFields&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;FSharpType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetRecordFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NonPublic&lt;/span&gt; &lt;span class="o"&gt;|||&lt;/span&gt; &lt;span class="nn"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Public&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toList&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;synEntries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;exprToAst&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;synEntries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mkLongIdent&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mkIdent&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;synExpr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynExpr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nn"&gt;SynExpr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Typed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;synExpr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;synTy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at &lt;code&gt;match ty with&lt;/code&gt; you can see that theres a special pattern match when the &lt;code&gt;ty&lt;/code&gt; is a &lt;code&gt;ProvidedRecord&lt;/code&gt; which calls &lt;code&gt;pr.RecordFields&lt;/code&gt; instead of &lt;code&gt;FSharpType.GetRecordFields&lt;/code&gt;.   This is because &lt;code&gt;GetRecordFields&lt;/code&gt; accesses reflection data that is not implemented fully in the &lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;Type Provider SDK&lt;/a&gt; this is due to custom attributes that FSharp.Core expect to be present.  &lt;/p&gt;

&lt;p&gt;Another aspect of this was transforming ProvidedTypes into AST nodes.  As well as the built in types in the &lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;Type Provider SDK&lt;/a&gt; I added several new types namely a &lt;code&gt;ProvidedUnion&lt;/code&gt;, &lt;code&gt;ProvidedUnionCase&lt;/code&gt; and a &lt;code&gt;ProvidedRecord&lt;/code&gt;.  These custom types along with normal Provided Types were mapped into AST fragments along with the quotations that had been transformed into AST nodes.  The combination of all these elements were used to create a complete AST which comprised of Modules, Records with member functions and Discriminated Unions with member functions.  &lt;/p&gt;

&lt;h4&gt;
  
  
  AST -&amp;gt; Source code
&lt;/h4&gt;

&lt;p&gt;We did not need the output to be a dll but actual source code as this was another of the main requirements, to do this I used the &lt;a href="https://github.com/fsprojects/fantomas"&gt;Fantomas&lt;/a&gt; library which allows you to use an AST as input and get back the source code the AST represents.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Summary of Challenges with Falanx
&lt;/h4&gt;

&lt;p&gt;Theres were quite a few challenges with Falanx, mainly around the usage and consumption of &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt;.  In other languages quoting and unquoting is a first class part off the language, however, this is not so with F# so there are lots of pitfalls whilst working with &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt; are really difficult to work with when you need to compose complex functions, even more so if you mix in &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/generics/statically-resolved-type-parameters"&gt;Statically Resolved Type Parameters&lt;/a&gt; and reflection.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt; loose detail when you use quotation literals &lt;em&gt;(sections of code enclosed by the &lt;code&gt;&amp;lt;@&lt;/code&gt;/&lt;code&gt;@&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;@@&lt;/code&gt;/&lt;code&gt;@@&amp;gt;&lt;/code&gt; operators&lt;/em&gt;).  For example pattern matching gets transformed into if else blocks, fixity information is lost so you don't know if an operator was called with infix or prefix notation etc.  &lt;em&gt;(I raised some of these issues as F# language suggestions: &lt;a href="https://github.com/fsharp/fslang-suggestions/issues/681"&gt;Add union match patterns to Expr&lt;/a&gt;, &lt;a href="https://github.com/fsharp/fslang-suggestions/issues/680"&gt;Add support for recording fixity in quoted literals&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;Quotations&lt;/a&gt; do not represent the full range of expressions possible with F#.  Types and Modules are not representable, Discriminated Union decomposition has no form of Quotation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The transformed &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; are not always elegant idiomatic F# code, mainly for the reason above and the fact that pattern matching is erased etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Splicing types into &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; can be really tricky especially if you are using a library that uses a lot of generic parameters such as Fleece.  Type inference in a library like Fleece makes it really nice to use with custom &lt;a href="https://github.com/mausch/Fleece#codec"&gt;applicative operators&lt;/a&gt; but defining generic functions with 5 or more generic types in the type signature is not fun at all.  Theres is an &lt;a href="https://github.com/fsharp/fslang-suggestions/issues/670"&gt;approved language proposal&lt;/a&gt; to add the splicing of types with the &lt;code&gt;~&lt;/code&gt; operator which would help with this somewhat.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Working with Provided Types from the &lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;Type Provider SDK&lt;/a&gt; can be really challenging with &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; as &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;quotations&lt;/a&gt; are backed by reflection and Provided Types have bare minimum reflection implemented.   There are often times where composing Quotations will fail at runtime due to a missing reflection implementation.  This sometimes required a patch to either the reflection implementation in the &lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;Type Provider SDK&lt;/a&gt; or a custom reflection implementation to extract information from the Provided Types.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in all it was quite an intense development processes with lots and lots of debugging and digging through FSharp.Core code and coming up with creative solutions &lt;em&gt;(Hacks!)&lt;/em&gt; to reflection issues.  I could probably write an entire article all about the pitfalls, tricks and tips of working with quotations without shooting your self in the foot with a blunderbuss.&lt;/p&gt;




&lt;h1&gt;
  
  
  Myriad Technical Overview
&lt;/h1&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Ok enough with Falanx what is Myriad Again?&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; is similar to the &lt;a href="https://github.com/ocaml-ppx/ppx_deriving"&gt;ppx_deriving&lt;/a&gt; extension for OCaml except that it's not as integrated as OCaml.  Although F# compiler integration is desirable for a tool like this there is the question of whether or not this would be in scope for the future direction of the F# language.  There is also the latency factor of writing and extension for the F# compiler and waiting for a release cycle so that it becomes generally available for everyone to use.  By leveraging MSBuild its possible to come close to some of the capabilities and functionality of &lt;a href="https://github.com/ocaml-ppx/ppx_deriving"&gt;ppx_deriving&lt;/a&gt;.  At the very least it progresses the notion of what more advanced macro like capabilities of F# could look like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ocaml-ppx/ppx_deriving"&gt;ppx_deriving&lt;/a&gt; works by allowing a type to extended by an arbitrary function, there are various built in plugins such as &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;eq&lt;/code&gt;, &lt;code&gt;ord&lt;/code&gt;, &lt;code&gt;enum&lt;/code&gt;, &lt;code&gt;iter&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;fold&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;yojson&lt;/code&gt; and &lt;code&gt;protobuf&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Another well known plugin is &lt;a href="https://github.com/janestreet/ppx_fields_conv"&gt;ppx_fields_conv&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generation of accessor and iteration functions for OCaml records.&lt;br&gt;
ppx_fields_conv is a ppx rewriter that can be used to define first class values representing record fields, and additional routines, to get and set record fields, iterate and fold over all fields of a record and create new record values.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was the basis for the idea of Myriad.  We will not be taking the full capability of &lt;a href="https://github.com/janestreet/ppx_fields_conv"&gt;ppx_fields_conv&lt;/a&gt; only a subset to show the potential of this approach.  More specifically we will be creating field accessor functions and a create function for each record in the input.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Usage And Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Input code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; works with an input file as the basis for code generation, specifically records within the input file are used in the code generation phase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Test2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; is invoked via the following addition to an F# project file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Compile&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Generated.fs"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!--1--&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MyriadFile&amp;gt;&lt;/span&gt;..\..\src\Example\Library.fs&lt;span class="nt"&gt;&amp;lt;/MyriadFile&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!--2--&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MyriadNameSpace&amp;gt;&lt;/span&gt;Test&lt;span class="nt"&gt;&amp;lt;/MyriadNameSpace&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!--3--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Compile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;Compile Include="..."&lt;/code&gt; element is used to specify the output name and also to make sure that the generated file is used during compilation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;MyriadFile&amp;gt;...&lt;/code&gt; is used to choose the file as input to the &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; code generation.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;MyriadNameSpace&amp;gt;...&lt;/code&gt; is used to specify a namespace to use for the generated code.  If this is omitted then the &lt;code&gt;RootNamespace&lt;/code&gt; from the project file is used.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Output code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;//        This code was generated by myriad.&lt;/span&gt;
&lt;span class="c1"&gt;//        Changes to this file will be lost when the code is regenerated.&lt;/span&gt;
&lt;span class="c1"&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="k"&gt;rec&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;three&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;four&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;
          &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;
          &lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;
          &lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Test2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;
          &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The technical aspects of this project derive from four main areas: parsing, AST construction, code output and build integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parsing
&lt;/h2&gt;

&lt;p&gt;The first step is gathering information from the input file which is easily done using &lt;a href="https://fsharp.github.io/FSharp.Compiler.Service/untypedtree.html"&gt;FSharp.Compiler.Services&lt;/a&gt;.  Its easy enough to extract the AST from a piece of code using something such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test.fs"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fileText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReadAllText&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FSharpChecker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;projOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetProjectOptionsFromScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RunSynchronously&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;parsingOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetParsingOptionsFromProjectOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;projOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;parseFileResults&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ParseFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsingOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RunSynchronously&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;parseFileResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ParseTree&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;failwith&lt;/span&gt; &lt;span class="s2"&gt;"Something went wrong during parsing!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;checker&lt;/code&gt; is created and &lt;code&gt;projectOptions&lt;/code&gt; are created using the &lt;code&gt;filename&lt;/code&gt; and &lt;code&gt;fileText&lt;/code&gt; as input.&lt;br&gt;
Now the checker can be used to extract an ast by first creating &lt;code&gt;parsingOptions&lt;/code&gt; and passing them to the &lt;code&gt;checker.ParseFile&lt;/code&gt;, this function returns an option which we pattern match, throwing an exception if there is no Ast present.  &lt;/p&gt;

&lt;p&gt;Now that we have the Ast we can use more pattern matching to try and find Ast nodes that we are interested in.  This can be done using a small section of dense pattern matching and decomposition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;ParsedInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImplFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ParsedImplFileInput&lt;/span&gt;&lt;span class="o"&gt;(_,_,_,_,_,&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;,_))&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nc"&gt;SynModuleOrNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespaceIdent&lt;/span&gt;&lt;span class="o"&gt;,_,_,&lt;/span&gt;&lt;span class="n"&gt;moduleDecls&lt;/span&gt;&lt;span class="o"&gt;,_,_,_,_)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;modules&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;moduleDecl&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;moduleDecls&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;moduleDecl&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;SynModuleDecl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;,_)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nc"&gt;TypeDefn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ComponentInfo&lt;/span&gt;&lt;span class="o"&gt;(_,_,_,&lt;/span&gt;&lt;span class="n"&gt;recordIdent&lt;/span&gt;&lt;span class="o"&gt;,_,_,_,_),&lt;/span&gt; &lt;span class="n"&gt;typeDefRepr&lt;/span&gt;&lt;span class="o"&gt;,_,_)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;typeDefRepr&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
                    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;SynTypeDefnRepr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Simple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;SynTypeDefnSimpleRepr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;(_,&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;,_),_)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespaceIdent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;recordIdent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet you can see that we traverse the AST first decomposing &lt;code&gt;ParsedInput.ImplFile&lt;/code&gt;, we do this so that we don't have to extract further information in another match such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;ParsedInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImplFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;pu&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ParsedImplFileInput&lt;/span&gt;&lt;span class="o"&gt;(_,_,_,_,_,&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;,_)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can loop through the modules/namespaces.  We then drill deeper until we find type definitions within the module.  Once we have found a type definition we can then match on a record node which is a &lt;code&gt;SynTypeDefnSimpleRepr.Record&lt;/code&gt; type.  Once we have found a record we can extract and yield and parameters that we need for the generator.  In this instance all we need is the parent namespace which we can find from &lt;code&gt;SynModuleOrNamespace(namespaceIdent,_,_,_,_,_,_,_)&lt;/code&gt;, the record identifier which we find in the type definitions &lt;code&gt;ComponentInfo&lt;/code&gt;:  &lt;code&gt;TypeDefn(ComponentInfo(_,_,_,recordIdent,_,_,_,_),_,_,_)&lt;/code&gt;.  The final parameter we need is the fields of the record which are in the record definition itself: &lt;code&gt;SynTypeDefnSimpleRepr.Record(_,fields,_)&lt;/code&gt;.  In this section you can see that we heavily used pattern matching and discriminated union decomposition, which are ideal for this particular task.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Ast Construction
&lt;/h2&gt;

&lt;p&gt;Now that we have the information we need we can now go about constructing the modules and functions that we want to generate.  &lt;/p&gt;

&lt;p&gt;To help with AST construction we use a library called &lt;a href="https://github.com/ctaggart/FsAst"&gt;FSAst&lt;/a&gt;.  I also used this in Falanx but thought I would explain it more detail here.  &lt;/p&gt;

&lt;p&gt;The principle behind &lt;a href="https://github.com/ctaggart/FsAst"&gt;FsAst&lt;/a&gt; is that it wraps common AST nodes with record types that have default values, this allows us to use record update syntax.  Most of the AST nodes have a lot of parameters and it can be annoying and cumbersome to construct them.  &lt;/p&gt;

&lt;p&gt;For example this is an example of &lt;code&gt;Let x = 42&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Let is a node of the type &lt;code&gt;SynModuleDecl&lt;/code&gt;, here is the definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nc"&gt;SynModuleDecl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;ModuleAbbrev&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Ident&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;longId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LongIdent&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;NestedModule&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;SynComponentInfo&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;isRecursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;SynModuleDecls&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Let&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;isRecursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;SynBinding&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;DoExpr&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;SequencePointInfoForBinding&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;SynExpr&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Types&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;SynTypeDefn&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;SynExceptionDefn&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Open&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;longDotId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LongIdentWithDots&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Attributes&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;SynAttributes&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;HashDirective&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;ParsedHashDirective&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;NamespaceFragment&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;SynModuleOrNamespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The single Let binding &lt;code&gt;Let x = 42&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nc"&gt;Let&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Binding&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;NormalBinding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,[],&lt;/span&gt;
        &lt;span class="nc"&gt;PreXmlDoc&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="nn"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;FSharp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Compiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Ast&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nc"&gt;XmlDocCollector&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;SynValData&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;SynValInfo&lt;/span&gt; &lt;span class="o"&gt;([],&lt;/span&gt;&lt;span class="nc"&gt;SynArgInfo&lt;/span&gt; &lt;span class="o"&gt;([],&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;Named&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Wild&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;IsSynthetic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;IsSynthetic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;Const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;IsSynthetic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;IsSynthetic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;SequencePointAtBinding&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;IsSynthetic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)],&lt;/span&gt;
    &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;IsSynthetic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On its own it would be defined as &lt;code&gt;SynModuleDecl.Let(false, bindings, range)&lt;/code&gt;, which would require the construction of a list of Bindings, a Binding is defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nc"&gt;SynBinding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Binding&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
    &lt;span class="n"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynAccess&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynBindingKind&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;mustInline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;isMutable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynAttributes&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;xmlDoc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PreXmlDoc&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;valData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynValData&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;headPat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynPat&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;returnInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynBindingReturnInfo&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynExpr&lt;/span&gt;  &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;
    &lt;span class="n"&gt;seqPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SequencePointInfoForBinding&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nn"&gt;SynBinding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Binding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;NormalBinding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;PreXmlDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;XmlDocCollector&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;SynValData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SynValInfo&lt;/span&gt;&lt;span class="o"&gt;([],&lt;/span&gt; &lt;span class="nc"&gt;SynArgInfo&lt;/span&gt; &lt;span class="o"&gt;([],&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Named&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Wild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tmp.fsx, range.zero, IsSynthetic=false, "&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="s2"&gt;", false, None, "&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt;&lt;span class="s2"&gt;", range.zero, IsSynthetic=false),
    None,
    Const (Int32, 42,"&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt;&lt;span class="s2"&gt;", range.zero, IsSynthetic=false),
    "&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt;&lt;span class="s2"&gt;", range.zero, IsSynthetic=false,
    SequencePointAtBinding("&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsx&lt;/span&gt;&lt;span class="s2"&gt;", range.zero, IsSynthetic=false)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that defining these nodes can get complicated really quickly.  With &lt;a href="https://github.com/ctaggart/FsAst"&gt;FsAst&lt;/a&gt; we can define the above Let AST fragment like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nn"&gt;SynModuleDecl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;SynBindingRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Let&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="s2"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateWild&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Expr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynExpr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateConst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;SynConst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes constructing aST fragments a lot easier!&lt;/p&gt;

&lt;p&gt;Here is a snippet of code from &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; which create a field mapping for a record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;createMap&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LongIdent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SynField&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToRcd&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fieldName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;failwith&lt;/span&gt; &lt;span class="s2"&gt;"no field name"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; 

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;recordType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;LongIdentWithDots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idText&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SynType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLongIdent&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;varName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"x"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LongIdentWithDots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="n"&gt;fieldName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idText&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;named&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="n"&gt;varName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateWild&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateTyped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;named&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recordType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateParen&lt;/span&gt;

        &lt;span class="nn"&gt;SynPatRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLongIdent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LongIdentWithDots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;varName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;fieldName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nn"&gt;SynExpr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLongIdent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;valData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;argInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynArgInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateIdString&lt;/span&gt; &lt;span class="s2"&gt;"x"&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;valInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SynValInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SynValInfo&lt;/span&gt;&lt;span class="o"&gt;([[&lt;/span&gt;&lt;span class="n"&gt;argInfo&lt;/span&gt;&lt;span class="o"&gt;]],&lt;/span&gt; &lt;span class="nn"&gt;SynArgInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nn"&gt;SynValData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SynValData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nn"&gt;SynModuleDecl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateLet&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="nn"&gt;SynBindingRcd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Let&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
                                &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;
                                &lt;span class="nc"&gt;Expr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt;
                                &lt;span class="nc"&gt;ValData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valData&lt;/span&gt; &lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me run through the sections that make up a Let binding, lets use this an an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Test1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Pattern
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Pattern&lt;/code&gt; is the bindings name, in this case its: &lt;code&gt;one (x : Test1)&lt;/code&gt;&lt;br&gt;
We create a &lt;code&gt;LongIdentifier&lt;/code&gt; from the fieldNames.idText as the name of the Let binding will be the same as the field name, we then make an argument using &lt;code&gt;"x"&lt;/code&gt; as the &lt;code&gt;varName&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Expr
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Expr&lt;/code&gt; is the expression that you are binding to the name, so this is: &lt;code&gt;x.one&lt;/code&gt;, which is essentially just a &lt;code&gt;LongIdentWithDots&lt;/code&gt; of &lt;code&gt;varName&lt;/code&gt; &lt;code&gt;.&lt;/code&gt; &lt;code&gt;fieldName&lt;/code&gt;.  &lt;/p&gt;
&lt;h4&gt;
  
  
  ValData
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ValData&lt;/code&gt; Is information about the argument names and other metadata for a parameter for a member or function.  Such as if the parameter optional or any attributes applied to the parameter.  In this instance we just add the identifier for the argument.  &lt;/p&gt;

&lt;p&gt;Using FsAst makes things a lot easier to build F# AST's with code, but there is still a lot of improvements that could be made with &lt;code&gt;Ident&lt;/code&gt; creation and other areas, there are possibly lots of functions withing the compiler that could be exposed to help with this too.   &lt;/p&gt;
&lt;h2&gt;
  
  
  Code Output
&lt;/h2&gt;

&lt;p&gt;Actual code generation can be done using the F# formatter tool &lt;a href="https://github.com/fsprojects/fantomas"&gt;Fantomas&lt;/a&gt;.  &lt;a href="https://github.com/fsprojects/fantomas"&gt;Fantomas&lt;/a&gt; has an API call that accepts an AST and formats the code that it represents.  All we have to do is make a call to that API to get back formatted source code and append it onto a header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sourceCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Fantomas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;CodeFormatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FormatAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fantomasConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can now have a header inserted and be written to a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;   &lt;span class="s2"&gt;"//------------------------------------------------------------------------------"&lt;/span&gt;
        &lt;span class="s2"&gt;"//        This code was generated by myriad."&lt;/span&gt;
        &lt;span class="s2"&gt;"//        Changes to this file will be lost when the code is regenerated."&lt;/span&gt;
        &lt;span class="s2"&gt;"//------------------------------------------------------------------------------"&lt;/span&gt;
        &lt;span class="n"&gt;formattedCode&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat&lt;/span&gt; &lt;span class="nn"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NewLine&lt;/span&gt;

&lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WriteAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MSBuild integration
&lt;/h2&gt;

&lt;p&gt;Wrapping the parsing and generation of code in a manner that is easy to use is done via an MSBuild extension, this gives a close approximation to the use of &lt;a href="https://github.com/ocaml-ppx/ppx_deriving"&gt;ppx_deriving&lt;/a&gt; and its role within the OCaml ecosystem.  &lt;/p&gt;

&lt;p&gt;This is achieved by adding two child attributes to the &lt;code&gt;Compile&lt;/code&gt; MSBuild element as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Compile&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Generated.fs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MyriadFile&amp;gt;&lt;/span&gt;..\..\src\Example\Library.fs&lt;span class="nt"&gt;&amp;lt;/MyriadFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MyriadNameSpace&amp;gt;&lt;/span&gt;Test&lt;span class="nt"&gt;&amp;lt;/MyriadNameSpace&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Compile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;Compile Include="Generated.fs" &amp;gt;&lt;/code&gt; element is used to specify the output name and also to make sure that the generated file is used during compilation.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;MyriadFile&amp;gt;..\..\src\Example\Library.fs&amp;lt;/MyriadFile&amp;gt;&lt;/code&gt; is used to choose the file as input to the code generation.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;MyriadNameSpace&amp;gt;Test&amp;lt;/MyriadNameSpace&amp;gt;&lt;/code&gt; is used to specify a namespace to use for the generated code.  If this is omitted then &lt;code&gt;RootNamespace&lt;/code&gt; is used.  &lt;/p&gt;

&lt;h3&gt;
  
  
  _MyriadSdkFilesList Target
&lt;/h3&gt;

&lt;p&gt;In order for the integration to occur &lt;code&gt;MyriadFile&lt;/code&gt; and &lt;code&gt;MyriadNameSpace&lt;/code&gt; have to be processed by the MSBuild extension to form a list of &lt;code&gt;Compile&lt;/code&gt; element extensions that we can then use to form as an input to a CLI/Command line tool.  This is done in the &lt;code&gt;_MyriadSdkFilesList&lt;/code&gt; Target, this first part is shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Target&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"_MyriadSdkFilesList"&lt;/span&gt; &lt;span class="na"&gt;BeforeTargets=&lt;/span&gt;&lt;span class="s"&gt;"MyriadSdkGenerateInputCache"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MyriadSource&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"%(Compile.MyriadFile)"&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '%(Compile.MyriadFile)' != '' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;OutputPath&amp;gt;&lt;/span&gt;$([System.IO.Path]::GetFullPath('%(Compile.FullPath)'))&lt;span class="nt"&gt;&amp;lt;/OutputPath&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Namespace&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '%(Compile.MyriadNamespace)' != '' "&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;%(Compile.MyriadNamespace)&lt;span class="nt"&gt;&amp;lt;/Namespace&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Namespace&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '%(Compile.MyriadNamespace)' == '' "&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;$(RootNamespace)&lt;span class="nt"&gt;&amp;lt;/Namespace&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/MyriadSource&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MyriadCodegen&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"%(MyriadSource.FullPath)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;OutputPath&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '%(MyriadSource.OutputPath)' != '' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;$([System.IO.Path]::GetFullPath('%(MyriadSource.OutputPath)'))&lt;span class="nt"&gt;&amp;lt;/OutputPath&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;OutputPath&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '%(MyriadSource.OutputPath)' == '' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;%(MyriadSource.FullPath).fs&lt;span class="nt"&gt;&amp;lt;/OutputPath&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Namespace&amp;gt;&lt;/span&gt;%(MyriadSource.Namespace)&lt;span class="nt"&gt;&amp;lt;/Namespace&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/MyriadCodegen&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;_MyriadSdkCodeGenInputCache&amp;gt;&lt;/span&gt;$(IntermediateOutputPath)$(MSBuildProjectFile).FalanxSdkCodeGenInputs.cache&lt;span class="nt"&gt;&amp;lt;/_MyriadSdkCodeGenInputCache&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first gather a list of files for &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; to process.  We do this by creating an &lt;code&gt;ItemGroup&lt;/code&gt; which is a list of &lt;code&gt;MyriadSource&lt;/code&gt; elements, only &lt;code&gt;Compile&lt;/code&gt; elements that have a &lt;code&gt;MyriadFile&lt;/code&gt; node are processed, this is done via the &lt;code&gt;Condition&lt;/code&gt; attribute: &lt;code&gt;Condition=" '%(Compile.MyriadFile)' != ''&lt;/code&gt;.  The &lt;code&gt;MyriadSource&lt;/code&gt; element is formed from three pieces of information.  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Include&lt;/code&gt; attribute is the &lt;code&gt;MyriadFile&lt;/code&gt; element we include in the MSBuild file.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;OutputPath&lt;/code&gt; element is full path for the &lt;code&gt;Compile&lt;/code&gt; elements &lt;code&gt;Include&lt;/code&gt; attribute, this is also known as &lt;code&gt;Identity&lt;/code&gt;&lt;br&gt;
The &lt;code&gt;Namespace&lt;/code&gt; element is either the &lt;code&gt;%(Compile.MyriadNamespace)&lt;/code&gt; if it is present or the &lt;code&gt;$(RootNamespace)&lt;/code&gt; if it is not.  &lt;/p&gt;



&lt;p&gt;Now that we have created an &lt;code&gt;ItemGroup&lt;/code&gt; containing &lt;code&gt;MyriadSource&lt;/code&gt; elements we can refine this a little, you could fold these changes into the &lt;code&gt;MyriadSource&lt;/code&gt; &lt;code&gt;ItemGroup&lt;/code&gt; but it is easier to create two &lt;code&gt;ItemGroup&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;We create a new &lt;code&gt;ItemGroup&lt;/code&gt; called &lt;code&gt;MyriadCodegen&lt;/code&gt; which references &lt;code&gt;MyriadSource&lt;/code&gt; for its &lt;code&gt;Include&lt;/code&gt; attribute.  There are also &lt;code&gt;Condition&lt;/code&gt; attributes to check the &lt;code&gt;OutputPath&lt;/code&gt; is not empty and also another to ensure that if it is empty to just set it to the input file.   This would mean that the input file itself would be processed and changed rather than being written to another file.  &lt;/p&gt;
&lt;h3&gt;
  
  
  MyriadSdkGenerateCode Target
&lt;/h3&gt;

&lt;p&gt;The final step is to invoke the CLI tool with all the information we have gathered in the &lt;code&gt;MyriadSdkGenerateCode&lt;/code&gt; target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MyriadSdkGenerateCodeDependsOn&amp;gt;&lt;/span&gt;$(MyriadSdkGenerateCodeDependsOn);ResolveReferences;MyriadSdkGenerateInputCache&lt;span class="nt"&gt;&amp;lt;/MyriadSdkGenerateCodeDependsOn&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Target&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"MyriadSdkGenerateCode"&lt;/span&gt;
        &lt;span class="na"&gt;DependsOnTargets=&lt;/span&gt;&lt;span class="s"&gt;"$(MyriadSdkGenerateCodeDependsOn)"&lt;/span&gt; 
        &lt;span class="na"&gt;BeforeTargets=&lt;/span&gt;&lt;span class="s"&gt;"CoreCompile"&lt;/span&gt;
        &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(DesignTimeBuild)' != 'true' "&lt;/span&gt;
        &lt;span class="na"&gt;Inputs=&lt;/span&gt;&lt;span class="s"&gt;"@(MyriadCodegen);$(_MyriadSdkCodeGenInputCache);$(MyriadSdk_Generator_Exe)"&lt;/span&gt;
        &lt;span class="na"&gt;Outputs=&lt;/span&gt;&lt;span class="s"&gt;"%(MyriadCodegen.OutputPath)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;_MyriadSdk_InputFileName&amp;gt;&lt;/span&gt;%(MyriadCodegen.Identity)&lt;span class="nt"&gt;&amp;lt;/_MyriadSdk_InputFileName&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;_MyriadSdk_OutputFileName&amp;gt;&lt;/span&gt;%(MyriadCodegen.OutputPath)&lt;span class="nt"&gt;&amp;lt;/_MyriadSdk_OutputFileName&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;_MyriadSdk_Namespace&amp;gt;&lt;/span&gt;%(MyriadCodegen.Namespace)&lt;span class="nt"&gt;&amp;lt;/_MyriadSdk_Namespace&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MyriadSdk_Args&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;'--inputfile "$(_MyriadSdk_InputFileName)"'&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MyriadSdk_Args&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;'--outputfile "$(_MyriadSdk_OutputFileName)"'&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MyriadSdk_Args&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;'--namespace "$(_MyriadSdk_Namespace)"'&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Use dotnet to execute the process. --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Exec&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"$(MyriadSdk_Generator_ExeHost)&amp;amp;quot;$(MyriadSdk_Generator_Exe)&amp;amp;quot; @(MyriadSdk_Args -&amp;gt; '%(Identity)', ' ')"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;DependsOnTargets&lt;/code&gt; attribute is used to ensure that anything contained in the &lt;code&gt;MyriadSdkGenerateCodeDependsOn&lt;/code&gt; element is ran before this Target.&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;MyriadSdkGenerateCode&lt;/code&gt; &lt;code&gt;Target&lt;/code&gt; element there are &lt;code&gt;Inputs&lt;/code&gt; and &lt;code&gt;Outputs&lt;/code&gt; attributes, these are used to determine when &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; needs to run.  An item is considered up-to-date if its output file is the same age or newer than its input file or files.  &lt;/p&gt;

&lt;p&gt;We create a &lt;code&gt;PropertyGroup&lt;/code&gt; to contain the command line parameters &lt;code&gt;_MyriadSdk_InputFileName&lt;/code&gt;, &lt;code&gt;_MyriadSdk_OutputFileName&lt;/code&gt; and &lt;code&gt;_MyriadSdk_Namespace&lt;/code&gt; using the corresponding elements from the  &lt;code&gt;_MyriadSdkFilesList&lt;/code&gt; Targets ItemGroup &lt;code&gt;MyriadCodegen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;we now create an &lt;code&gt;ItemGroup&lt;/code&gt; which has within it three &lt;code&gt;MyriadSdk_Args&lt;/code&gt; elements that we need to invoke the code generator with.&lt;/p&gt;

&lt;p&gt;Finally we execute the code generator with &lt;code&gt;Exec&lt;/code&gt; invoking the CLI too, with the parameters from &lt;code&gt;MyriadSdk_Args&lt;/code&gt; &lt;code&gt;Include&lt;/code&gt; attribute via the MSBuild function &lt;code&gt;@(MyriadSdk_Args -&amp;gt; '%(Identity)', ' ')&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One thing that was not discussed in this section was the &lt;code&gt;_MyriadSdkCodeGenInputCache&lt;/code&gt; that was referenced in both targets above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Target&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"MyriadSdkGenerateInputCache"&lt;/span&gt; &lt;span class="na"&gt;DependsOnTargets=&lt;/span&gt;&lt;span class="s"&gt;"ResolveAssemblyReferences;_MyriadSdkFilesList"&lt;/span&gt; &lt;span class="na"&gt;BeforeTargets=&lt;/span&gt;&lt;span class="s"&gt;"MyriadSdkGenerateCode"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MyriadSdk_CodeGenInputs&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"@(MyriadCodegen);@(ReferencePath);$(MyriadSdk_Generator_Exe)"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;Hash&lt;/span&gt; &lt;span class="na"&gt;ItemsToHash=&lt;/span&gt;&lt;span class="s"&gt;"@(MyriadSdk_CodeGenInputs)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Output&lt;/span&gt; &lt;span class="na"&gt;TaskParameter=&lt;/span&gt;&lt;span class="s"&gt;"HashResult"&lt;/span&gt; &lt;span class="na"&gt;PropertyName=&lt;/span&gt;&lt;span class="s"&gt;"MyriadSdk_UpdatedInputCacheContents"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Hash&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;WriteLinesToFile&lt;/span&gt; &lt;span class="na"&gt;Overwrite=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;File=&lt;/span&gt;&lt;span class="s"&gt;"$(_MyriadSdkCodeGenInputCache)"&lt;/span&gt; &lt;span class="na"&gt;Lines=&lt;/span&gt;&lt;span class="s"&gt;"$(MyriadSdk_UpdatedInputCacheContents)"&lt;/span&gt; &lt;span class="na"&gt;WriteOnlyWhenDifferent=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This target generates a hash using &lt;code&gt;@(MyriadCodegen);@(ReferencePath);$(MyriadSdk_Generator_Exe)&lt;/code&gt; as an input.  If any of those changes then a different hash will be written to the output file via &lt;code&gt;&amp;lt;WriteLinesToFile Overwrite="true" File="$(_MyriadSdkCodeGenInputCache)"&lt;/code&gt;.  This captures the total set of all inputs to the code generator.  This is based on the _GenerateCompileDependencyCache target from the .NET project system, which was used as a reference.  You can find this in the .Net project system &lt;a href="https://github.com/Microsoft/msbuild/blob/adb180d394176f36aca1cc2eac4455fef564739f/src/Tasks/Microsoft.Common.CurrentVersion.targets#L3407"&gt;source&lt;/a&gt;. &lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Wow this was a lot longer than I thought it would be, I hope I didn't ramble too much, its quite a large area once you try to dissect the details.  This are probably multiple essays I could write on each topic.  &lt;/p&gt;

&lt;p&gt;I think the key points I summed up at the end of &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; were that quotations were not easy to work with, and thats certainly true if you try pushing them right to their limits.  I think &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;Type Providers&lt;/a&gt; and applicative programming with many generic parameters certainly does that!&lt;/p&gt;

&lt;p&gt;Falanx was a great project that showed that even out of the box libraries can be used to compose quite a complex project.  Building up a quotations from both literals and expressions takes a lot of time and often you have to run a lot of debug cycles to get things right.  &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; built on that by providing a simpler solution of composing the AST directly.  I think there is some scope for a middle ground between the two where a quotation literals could be used as shortcut to provided an AST snippet much in the same way you can do this with &lt;a href="https://haxe.org"&gt;Haxe&lt;/a&gt; &lt;a href="https://haxe.org/manual/macro-reification-expression.html"&gt;Expression Reification&lt;/a&gt;.  Its sort of similar to the way you can use quotations to extract a &lt;code&gt;MethodInfo&lt;/code&gt;.  This is used quote a bit in &lt;a href="https://github.com/7sharp9/falanx/blob/master/src/Falanx.Machinery/Expr.fs#L199"&gt;Falanx.Machinery&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;@@&lt;/span&gt; &lt;span class="n"&gt;writeEmbedded&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;@@&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Expr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;methodof&lt;/span&gt;
&lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Expr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callStatic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think some creative uses of moving to and from quotations and the AST would allow a lot more flexibility in meta-programming.  &lt;/p&gt;

&lt;p&gt;You can find the repositories for both &lt;a href="https://github.com/7sharp9/myriad"&gt;Myriad&lt;/a&gt; and &lt;a href="https://github.com/7sharp9/falanx"&gt;Falanx&lt;/a&gt; on github as soon as Ive made this post public, they are both also available on Nuget too: &lt;a href="https://www.nuget.org/packages/Falanx.Sdk/"&gt;Falanx.Sdk&lt;/a&gt;/&lt;a href="https://www.nuget.org/packages/Myriad.Sdk/"&gt;Myriad.Sdk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post on applied meta-programming and hope to expand on this subject and many others on my &lt;a href="https://www.youtube.com/channel/UC0kXc1f_WBYSklrElcPWzgg"&gt;YouTube channel&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Until next time!  &lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;p&gt;&lt;small&gt;&lt;br&gt;
&lt;a href="https://github.com/ocaml-ppx/ppx_deriving"&gt;1 Type-driven code generation for OCaml - ppx_deriving&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/janestreet/ppx_fields_conv"&gt;2 Generation of accessor and iteration functions for OCaml records&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://fsharp.github.io/FSharp.Compiler.Service/untypedtree.html"&gt;3 Compiler Services: Processing untyped syntax tree&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/fsprojects/fantomas"&gt;4 Fantomas F# source code formatter&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/Microsoft/msbuild/blob/adb180d394176f36aca1cc2eac4455fef564739f/src/Tasks/Microsoft.Common.CurrentVersion.targets#L3407"&gt;5 .NET project System:- _GenerateCompileDependencyCache&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/7sharp9/falanx"&gt;6 Falanx protobuf Code Generation&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://7sharp9.github.io/2015/07/12/2015-07-08-meta-matic/"&gt;7 Meta-matic&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/fsprojects/FSharp.TypeProviders.SDK"&gt;8 Type Provider SDK&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/"&gt;9 Type Providers&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://developers.google.com/protocol-buffers/"&gt;10 Protocol Buffers&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/mausch/Fleece"&gt;11 Fleece&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/ctaggart/froto"&gt;12 Froto&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/eiriktsarpalis/QuotationCompiler"&gt;13 Quotation Compiler&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/generics/statically-resolved-type-parameters"&gt;14 Statically Resolved Type Parameters&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations"&gt;15 Quotations&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/ctaggart/FsAst"&gt;16 FsAst&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/7sharp9/myriad"&gt;17 Myriad&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/channel/UC0kXc1f_WBYSklrElcPWzgg"&gt;18 My YouTube Channel&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://haxe.org"&gt;19 Haxe&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://haxe.org/manual/macro-reification-expression.html"&gt;20 Expression Reification&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/?tabs=netcore2x"&gt;21 CLI Tool&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions"&gt;22 Discriminated Unions&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/records"&gt;23 Records&lt;/a&gt;&lt;br&gt;
&lt;/small&gt;&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>metaprogramming</category>
    </item>
  </channel>
</rss>
