<?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: Romain Deneau</title>
    <description>The latest articles on DEV Community by Romain Deneau (@rdeneau).</description>
    <link>https://dev.to/rdeneau</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%2F134108%2F1ba901ce-c1bf-470f-ba4f-9328a49d8f83.jpeg</url>
      <title>DEV Community: Romain Deneau</title>
      <link>https://dev.to/rdeneau</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rdeneau"/>
    <language>en</language>
    <item>
      <title>Applying object-oriented design principles - In-memory configuration builder</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Mon, 01 Sep 2025 13:45:16 +0000</pubDate>
      <link>https://dev.to/rdeneau/applying-object-oriented-design-principles-in-memory-configuration-builder-log</link>
      <guid>https://dev.to/rdeneau/applying-object-oriented-design-principles-in-memory-configuration-builder-log</guid>
      <description>&lt;p&gt;Testing functionality that takes an XML or JSON file as input is no easy task. We'll see how to apply object-oriented design principles and modern programming language features to produce unit tests that are fun to write and easy to review. Code snippets will be written in C#.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem description
&lt;/h2&gt;

&lt;p&gt;The functionality in question here consists of parsing a section of an ASP.NET application's configuration defined in &lt;code&gt;appsettings*.json&lt;/code&gt; files. These files are read by the ASP.NET framework after configuring the application with an instruction such as &lt;code&gt;builder.Configuration.AddJsonFile($"appsettings.json", optional: false, reloadOnChange: true)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The configuration can then be accessed in a variety of ways. In our case, parsing the configuration section leads to a higher-level object and, more importantly, one in a valid state. For this reason, the most suitable way is to use an &lt;code&gt;IConfiguration&lt;/code&gt; object from the NuGet package &lt;code&gt;Microsoft.Extensions.Configuration.Abstractions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This object is not easily mockable for our unit tests, but Microsoft has thought of us: &lt;code&gt;ConfigurationBuilder&lt;/code&gt; - from the NuGet package &lt;code&gt;Microsoft.Extensions.Configuration&lt;/code&gt; - is a convenient way of creating an in-memory configuration from a key-value dictionary, especially useful for unit testing, as it avoids file I/O and external dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&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;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;...;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jsonConfiguration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The disadvantage is that the tree structure is lost: the path of entries in the configuration is encoded in the key, and in an atypical format: each level is separated from its parent by the &lt;code&gt;':'&lt;/code&gt; character. We'd like to build this configuration in a syntax that makes it easy to bridge the gap with the real configuration written in JSON, and that doesn't require knowledge of the subtleties of input path encoding.&lt;/p&gt;

&lt;p&gt;The configuration to build here has the following JSON format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AwsSecretManager"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"RegionName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"***"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SecretName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"****"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PartnerKeyName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Optional.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;defined&lt;/span&gt;&lt;span class="w"&gt;  
      &lt;/span&gt;&lt;span class="nl"&gt;"Login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyPartnerLogin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Login"&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="nl"&gt;"Password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyPartnerPassword"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password"&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;  
    &lt;/span&gt;&lt;span class="nl"&gt;"AwsCredentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"Source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Basic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AccessKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~~~~"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"SecretKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~~~~~~"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"AwsCredentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Environment"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do this, there's nothing like experimentation: we write the construction code for this configuration section, testing this syntax from both sides: on the one hand, does the usage meet our needs? On the other hand, is it easy to implement, while at the same time preventing us from writing buggy code? The right compromise comes after a few attempts. Let's look at the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax on the usage side
&lt;/h2&gt;

&lt;p&gt;Let's start with an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AwsSecretManager"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RegionName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"***"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SecretName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"****"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PartnerKeyName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyPartnerLogin"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyPartnerPassword"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AwsCredentials"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Source"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Environment"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToConfiguration&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This syntax is based on two helpers and one method:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Configuration.Value(key, value)&lt;/code&gt; helper defines an entry in a section.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Configuration.Section(name, ..entries)&lt;/code&gt; helper defines a section with the specified name, containing the given entries. The &lt;code&gt;entries&lt;/code&gt; parameter is a &lt;code&gt;param&lt;/code&gt; array.&lt;/li&gt;
&lt;li&gt;Both helpers use a short naming, eliminating verbs like &lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;Make&lt;/code&gt;, &lt;code&gt;Create&lt;/code&gt; to simplify the syntax without compromising the clarity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ToConfiguration()&lt;/code&gt; is used to define the &lt;code&gt;IConfiguration&lt;/code&gt; required as input to unit tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach offers several key advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No JSON Required:&lt;/strong&gt; Configuration is constructed directly in C#, eliminating the need to embed, parse, or comment JSON within your code. The resulting unit tests are more robust and have better performances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Natural Nesting:&lt;/strong&gt; The syntax's structure closely matches the nesting found in JSON. Sections can contain other sections or entries, making the configuration tree intuitive and easy to follow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight Syntax:&lt;/strong&gt; The syntax does not rely on the &lt;code&gt;new&lt;/code&gt; keyword, braces &lt;code&gt;{}&lt;/code&gt; or square brackets &lt;code&gt;[]&lt;/code&gt;, resulting in concise and readable code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Clarity:&lt;/strong&gt; The syntax is explicit: qualified use with &lt;code&gt;Configuration.&lt;/code&gt; removes any doubt about the domain involved.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation design
&lt;/h2&gt;

&lt;p&gt;Let's take a look at the implementation behind this syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;Entry&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;Key&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;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEntries&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetEnumerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IEntries&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entry&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;IEnumerator&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnumerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetEnumerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;IConfigurationRoot&lt;/span&gt; &lt;span class="nf"&gt;ToConfiguration&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;new&lt;/span&gt; &lt;span class="nf"&gt;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToDictionary&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;=&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;Key&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;=&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;Value&lt;/span&gt;&lt;span class="p"&gt;)!)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Entries&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEntries&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_entries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;&amp;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;{&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;entries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetEnumerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;_entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsEnumerable&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetEnumerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Entries&lt;/span&gt; &lt;span class="nf"&gt;Collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Entry&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="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;params&lt;/span&gt; &lt;span class="n"&gt;IEntries&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;new&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="nf"&gt;SelectMany&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;=&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="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEntries&lt;/span&gt; &lt;span class="nf"&gt;Section&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;params&lt;/span&gt; &lt;span class="n"&gt;IEntries&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&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="s"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEntries&lt;/span&gt; &lt;span class="nf"&gt;Value&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;value&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;new&lt;/span&gt; &lt;span class="nf"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&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;Here are the steps I followed to arrive at this design:&lt;/p&gt;

&lt;p&gt;To encourage the qualified use of helpers, all the code is placed in a static class &lt;code&gt;Configuration&lt;/code&gt;. This is similar to what we do in F# to gather helpers into a module, although we lack the &lt;code&gt;RequireQualifiedAccess&lt;/code&gt; attribute to force qualification when using functions in the module.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Configuration&lt;/code&gt; will contain the two helpers &lt;code&gt;Value&lt;/code&gt; and &lt;code&gt;Section&lt;/code&gt; that are static methods. &lt;code&gt;Value&lt;/code&gt; constructs an instance of an &lt;code&gt;Entry&lt;/code&gt; record used to define a &lt;code&gt;Key, Value&lt;/code&gt; entry in configuration. &lt;code&gt;Section&lt;/code&gt; takes as input the name and content of the section, the content being entries and sub-sections. What should be the input and output parameter types?&lt;/p&gt;

&lt;p&gt;The output type of &lt;code&gt;Value&lt;/code&gt; and &lt;code&gt;Section&lt;/code&gt; must be compatible with the input type of &lt;code&gt;Section&lt;/code&gt;. So we need a common abstraction. The &lt;code&gt;ConfigurationBuilder&lt;/code&gt; and its &lt;code&gt;AddInMemoryCollection&lt;/code&gt; method allows us to consider a section as a simple collection of entries, hence the &lt;code&gt;IEntries&lt;/code&gt; interface which extends &lt;code&gt;IEnumerable&amp;lt;Entry&amp;gt;&lt;/code&gt;. A default implementation of &lt;code&gt;IEnumerable.GetEnumerator&lt;/code&gt; is provided: derived classes need only to implement &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;.GetEnumerator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We need a type implementing the &lt;code&gt;IEntries&lt;/code&gt; interface. We could create a &lt;code&gt;Section&lt;/code&gt; type, but we don't actually need one. As the section name can just be encoded in the entry keys, an &lt;code&gt;Entries&lt;/code&gt; type is sufficient. This is a class that encapsulates an &lt;code&gt;IEnumerable&amp;lt;Entry&amp;gt;&lt;/code&gt; in order to delegate the construction of the enumerator to it. This class can be private, hiding this implementation detail from &lt;code&gt;Configuration&lt;/code&gt; users.&lt;/p&gt;

&lt;p&gt;We have linked &lt;code&gt;Section&lt;/code&gt; to &lt;code&gt;IEntries&lt;/code&gt;. What can we do on the &lt;code&gt;Entry&lt;/code&gt; side to link it to &lt;code&gt;IEntries&lt;/code&gt;? The &lt;em&gt;Composite&lt;/em&gt; design pattern points the way. &lt;code&gt;Entry&lt;/code&gt; can be seen as a collection of a single entry: the type can thus implement the &lt;code&gt;IEntries&lt;/code&gt; interface, with a &lt;code&gt;GetEnumerator&lt;/code&gt; based on a simple &lt;code&gt;yield return this;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At this stage, we still need to manage the contents of a section, i.e. the aggregation of all entries and the encoding of the section name in the entry keys. This second aspect is handled directly by the &lt;code&gt;Section&lt;/code&gt; helper, while entry aggregation is delegated to a &lt;code&gt;Collect&lt;/code&gt; function in the &lt;code&gt;Entries&lt;/code&gt; class, to keep responsibilities clearly separated. &lt;code&gt;Collect&lt;/code&gt; creates a new instance of &lt;code&gt;Entries&lt;/code&gt; wrapping a call to &lt;code&gt;SelectMany&lt;/code&gt; to flatten the set of specified entries, each entry being mapped using the specified function &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design principles followed in the implementation
&lt;/h2&gt;

&lt;p&gt;Key design aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Inheritance:&lt;/strong&gt; The design avoids base classes, to favor composition over inheritance. For example, the &lt;code&gt;Entries&lt;/code&gt; class does not inherit from an existing collection, but wraps it and delegates to it the implementation of the enumeration of its elements. The use of default implementations in the &lt;code&gt;IEntries&lt;/code&gt; interface is at the limit of this principle, as it could be seen as inheritance, but it offers the advantage to avoid duplication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default Interface Methods and No Duplication:&lt;/strong&gt; The use of default method implementations (such as &lt;code&gt;GetEnumerator&lt;/code&gt;) in &lt;code&gt;IEntries&lt;/code&gt; interface allows code sharing without inheritance. &lt;code&gt;ToConfiguration&lt;/code&gt; could have been written as an extension method, but it's easier to centralize them all in one place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation:&lt;/strong&gt; Implementation details are hidden. Only the &lt;code&gt;IEntries&lt;/code&gt; interface and the &lt;code&gt;Entry&lt;/code&gt; record are exposed, while the concrete classe &lt;code&gt;Entries&lt;/code&gt; remains private. This would allow us to change our internal model, to rely on other implementations, without breaking the calling code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutability:&lt;/strong&gt; The objects involved in this design are all immutable, guaranteeing that they are supplied directly in a valid state that cannot be corrupted afterwards, in particular the key of an entry encoding the access path. The &lt;code&gt;entry&lt;/code&gt; type relies on the C# 9 &lt;code&gt;record&lt;/code&gt; to get the immutability for free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composite Pattern:&lt;/strong&gt; The &lt;code&gt;IEntries&lt;/code&gt; interface embodies the &lt;em&gt;Composite&lt;/em&gt; design pattern. This gives us the flexibility to combine as many inputs as we like.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This configuration builder provides a robust and flexible way to build configuration objects in C#, leveraging modern language features and design principles for clarity and maintainability.&lt;/p&gt;

&lt;p&gt;The investment in creating such APIs pays dividends in test maintainability—an area that is often overlooked in many codebases but crucial for long-term project health.&lt;/p&gt;

&lt;p&gt;Are you familiar with this type of design? If you haven't written one yourself, has this article motivated you to give it a try?&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>oop</category>
    </item>
    <item>
      <title>Writing F# computation expressions</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Fri, 22 Aug 2025 15:20:00 +0000</pubDate>
      <link>https://dev.to/rdeneau/writing-f-computation-expressions-10mh</link>
      <guid>https://dev.to/rdeneau/writing-f-computation-expressions-10mh</guid>
      <description>&lt;p&gt;This final article in the series dedicated to F# computation expressions completes what we have seen regarding writing F# computation expressions of any kind: &lt;a href="https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7#applicative"&gt;applicative&lt;/a&gt;, &lt;a href="https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7#monad"&gt;monadic&lt;/a&gt;, or &lt;a href="https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7#monoid"&gt;monoidal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;
Types

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt; wrapper type&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Internal&amp;lt;T&amp;gt;&lt;/code&gt; type&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Builder-less CE

&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;activity {}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Custom operations 🚀&lt;/li&gt;
&lt;li&gt;
Final words

&lt;ul&gt;
&lt;li&gt;Benefits ✅&lt;/li&gt;
&lt;li&gt;Limits ⚠️&lt;/li&gt;
&lt;li&gt;Guidelines 📃&lt;/li&gt;
&lt;li&gt;Tips 💡&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;🍔 Quiz&lt;/li&gt;
&lt;li&gt;🔗 Additional resources&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Types
&lt;/h2&gt;

&lt;p&gt;The CE builder method definitions can involve not 2 but 3 types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The wrapper type &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;Internal&amp;lt;T&amp;gt;&lt;/code&gt; type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;☝️ &lt;strong&gt;Note:&lt;/strong&gt; we continue to use the generic type notation &lt;code&gt;Xxx&amp;lt;T&amp;gt;&lt;/code&gt; for these types for convenience, even though it's an approximation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt; wrapper type
&lt;/h3&gt;

&lt;p&gt;Candidates for this type are either generic types or "container" types like &lt;code&gt;string&lt;/code&gt; as it contains &lt;code&gt;char&lt;/code&gt;s. In fact, any type itself can be used as the wrapper type for a CE, as it can be written as the &lt;code&gt;Identity&amp;lt;T&amp;gt;&lt;/code&gt; type: &lt;code&gt;type Identity&amp;lt;'t&amp;gt; = 't&lt;/code&gt;. This was the case for the &lt;code&gt;logger {}&lt;/code&gt; CE we saw in the first article of the series.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; is the type returned by the &lt;code&gt;Delay&lt;/code&gt; method. It is used when we want to delay the evaluation of an expression inside the CE's body.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Delay&lt;/code&gt; input parameter already involves this deferred evaluation as its type is &lt;code&gt;unit -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt;, the type of a thunk. Based on that, we have three possibilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Eager evaluation: &lt;code&gt;Delay&lt;/code&gt; consists in executing the thunk: &lt;code&gt;member _.Delay f = f()&lt;/code&gt;. In this case, &lt;code&gt;type Delayed&amp;lt;T&amp;gt; = M&amp;lt;T&amp;gt;&lt;/code&gt;. It is the default implementation when &lt;code&gt;Delay&lt;/code&gt; is not required and not specified.&lt;/li&gt;
&lt;li&gt;Deferred evaluation with no additional type: &lt;code&gt;Delay&lt;/code&gt; returns the thunk directly, without executing it. &lt;code&gt;Delay&lt;/code&gt; is just the identity function: &lt;code&gt;member _.Delay f = f&lt;/code&gt;. &lt;code&gt;type Delayed&amp;lt;T&amp;gt; = unit -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Deferred evaluation with an additional type: &lt;code&gt;Delay&lt;/code&gt; uses the thunk to build an instance of an additional type, usually just wrapping the thunk: &lt;code&gt;member _.Delay f = Delayed f&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the &lt;code&gt;Delay&lt;/code&gt; method is defined, some of the other methods of the builder must be adapted: &lt;code&gt;Run&lt;/code&gt;, &lt;code&gt;Combine&lt;/code&gt;, &lt;code&gt;While&lt;/code&gt;, &lt;code&gt;TryWith&lt;/code&gt;, &lt;code&gt;TryFinally&lt;/code&gt; must take into account that their input parameter has the &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type example: &lt;code&gt;eventually {}&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;In this example, adapted from the &lt;a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions" rel="noopener noreferrer"&gt;Microsoft documentation&lt;/a&gt;, we define a union type &lt;code&gt;Eventually&amp;lt;'t&amp;gt;&lt;/code&gt; used for both wrapper and delayed types:&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;Eventually&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Done&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;NotYetDone&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Eventually&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&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;EventuallyBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Return&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;Done&lt;/span&gt; &lt;span class="n"&gt;x&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;ReturnFrom&lt;/span&gt; &lt;span class="n"&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="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Done&lt;/span&gt;&lt;span class="bp"&gt;()&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;Delay&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;NotYetDone&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

    &lt;span class="k"&gt;member&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;Bind&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="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&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;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;Done&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;f&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;NotYetDone&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;NotYetDone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;member&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;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&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="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;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&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="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expr&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;eventually&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EventuallyBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output values are meant to be evaluated interactively, step by step:&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;step&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Done&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="nc"&gt;Done&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;NotYetDone&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&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;delayPrintMessage&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;NotYetDone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"Message %d"&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;Done&lt;/span&gt; &lt;span class="bp"&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;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventually&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;delayPrintMessage&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;delayPrintMessage&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&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;step1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;   &lt;span class="c1"&gt;// val step1: Eventually&amp;lt;int&amp;gt; = NotYetDone &amp;lt;fun:Bind@14-1&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;step2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step1&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;  &lt;span class="c1"&gt;// Message 1 ↩ val step2: Eventually&amp;lt;int&amp;gt; = NotYetDone &amp;lt;fun:Bind@14-1&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;step3&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step2&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;  &lt;span class="c1"&gt;// Message 2 ↩ val step3: Eventually&amp;lt;int&amp;gt; = Done 7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;Internal&amp;lt;T&amp;gt;&lt;/code&gt; type
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Return&lt;/code&gt;, &lt;code&gt;ReturnFrom&lt;/code&gt;, &lt;code&gt;Yield&lt;/code&gt;, &lt;code&gt;YieldFrom&lt;/code&gt;, &lt;code&gt;Zero&lt;/code&gt; methods can return a type internal to the CE. The &lt;code&gt;Combine&lt;/code&gt;, &lt;code&gt;Delay&lt;/code&gt;, and &lt;code&gt;Run&lt;/code&gt; methods are adapted to handle this type.&lt;/p&gt;

&lt;p&gt;For instance, we can review our &lt;code&gt;list {}&lt;/code&gt; CE (&lt;a href="https://dev.to/rdeneau/f-monoidal-computation-expressions-2l06#ce-monoidal-to-generate-a-collection"&gt;link&lt;/a&gt;) to use a &lt;code&gt;seq&lt;/code&gt; type internally, as it is done by the list comprehension:&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;ListSeqBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;singleton&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;YieldFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofList&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="o"&gt;([&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;thunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="n"&gt;thunk&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&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;listSeq&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ListSeqBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; the &lt;code&gt;Internal&amp;lt;T&amp;gt;&lt;/code&gt; type highlights the usefulness of &lt;code&gt;ReturnFrom&lt;/code&gt; and &lt;code&gt;YieldFrom&lt;/code&gt;, implemented as an &lt;em&gt;identity&lt;/em&gt; function until now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Builder-less CE
&lt;/h2&gt;

&lt;p&gt;Up to now, we've assumed that a specific type had to be defined to serve as a &lt;em&gt;Builder&lt;/em&gt; to create a computation expression. It turns out that this isn't necessary. In fact, any type, even an existing one, can be extended to support CE syntax: simply extend it using extension methods of a CE builder.&lt;/p&gt;

&lt;p&gt;Let's look at an example: the &lt;code&gt;activity {}&lt;/code&gt; CE. It was written by my teammate Loïc/Tarmil, creator and maintainer of &lt;a href="https://github.com/fsbolero/Bolero" rel="noopener noreferrer"&gt;Bolero&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The purpose of the &lt;code&gt;activity {}&lt;/code&gt; CE is to configure an &lt;code&gt;Activity&lt;/code&gt; (from &lt;code&gt;System.Diagnostics&lt;/code&gt;) with a lightweight convenient syntax.&lt;/p&gt;

&lt;p&gt;Given an &lt;code&gt;activity&lt;/code&gt; provided by any &lt;code&gt;ActivitySource&lt;/code&gt;, we would like to write something like that:&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;use&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Activities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StartActivity&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt;

&lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setStartTime&lt;/span&gt; &lt;span class="nn"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UtcNow&lt;/span&gt;
    &lt;span class="n"&gt;setTag&lt;/span&gt; &lt;span class="s2"&gt;"count"&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some preliminary remarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The type to extend to support CE syntax is &lt;code&gt;System.Diagnostics.Activity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The returned type is &lt;code&gt;unit&lt;/code&gt;: the CE is only performing a side effect to change/mutate the &lt;code&gt;activity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The CE involves implicit &lt;code&gt;yield&lt;/code&gt;s for each call to helper methods like &lt;code&gt;setStartTime&lt;/code&gt;, defined aside the extension methods.&lt;/li&gt;
&lt;li&gt;The internal functioning of the CE is based on the type &lt;code&gt;type ActivityAction = delegate of Activity -&amp;gt; unit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each helper creates an instance of &lt;code&gt;ActivityAction&lt;/code&gt; that defines the delayed change on the &lt;code&gt;activity&lt;/code&gt;. E.g. &lt;code&gt;let inline setStartTime time = ActivityAction(fun ac -&amp;gt; ac.SetStartTime(time) |&amp;gt; ignore)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Internally, the CE combines every yielded &lt;code&gt;ActivityAction&lt;/code&gt; that is created by the helpers. So, it's a monoidal CE.&lt;/li&gt;
&lt;li&gt;Externally, the CE looks like a &lt;code&gt;State&lt;/code&gt; monad, with a series of &lt;code&gt;Set&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here the full code listing:&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;ActivityAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;delegate&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;

&lt;span class="c1"&gt;// Helpers&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;([&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&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="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;_)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;ActivityAction&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;ac&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="n"&gt;ac&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;addLink&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;AddLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;setTag&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;SetTag&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="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;setStartTime&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;SetStartTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// CE Builder Methods&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;ActivityExtensions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;EditorBrowsable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EditorBrowsableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;)&amp;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="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Zero&lt;/span&gt;&lt;span class="o"&gt;(_:&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActivityAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;EditorBrowsable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EditorBrowsableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;)&amp;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="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Yield&lt;/span&gt;&lt;span class="o"&gt;(_:&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;EditorBrowsable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EditorBrowsableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;)&amp;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="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="o"&gt;(_:&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;ActivityAction&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;ac&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;EditorBrowsable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EditorBrowsableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;)&amp;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="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="o"&gt;(_:&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&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="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ActivityAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;EditorBrowsable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EditorBrowsableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;)&amp;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="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InlineIfLambda&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="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityAction&lt;/span&gt;&lt;span class="p"&gt;)&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;ac&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ac&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="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// ---&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Tests"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setStartTime&lt;/span&gt; &lt;span class="nn"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UtcNow&lt;/span&gt;
    &lt;span class="n"&gt;setTag&lt;/span&gt; &lt;span class="s2"&gt;"count"&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Desugaring&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="n"&gt;desugar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;ActivityExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;ActivityExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&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="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nn"&gt;ActivityExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nn"&gt;ActivityExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setStartTime&lt;/span&gt; &lt;span class="nn"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UtcNow&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="nn"&gt;ActivityExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&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="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="nn"&gt;ActivityExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setTag&lt;/span&gt; &lt;span class="s2"&gt;"count"&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&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;☝️ &lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Delay&lt;/code&gt; method evaluates the thunk &lt;code&gt;f: unit -&amp;gt; ActivityAction&lt;/code&gt; to return the wrapped &lt;code&gt;ActivityAction&lt;/code&gt; already involving a deferred action.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Combine&lt;/code&gt; method is used to chain two &lt;code&gt;ActivityAction&lt;/code&gt;s into one, calling each one in series.&lt;/li&gt;
&lt;li&gt;The final &lt;code&gt;Run&lt;/code&gt; is the only method really using the input &lt;code&gt;activity&lt;/code&gt;. It evaluates the built &lt;code&gt;ActivityAction&lt;/code&gt;, resulting in the change/mutation of the &lt;code&gt;activity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The extension methods are marked as not &lt;code&gt;EditorBrowsable&lt;/code&gt; to improve the developer experience: when we use dot notation on the &lt;code&gt;activity&lt;/code&gt;, the extension methods are not suggested for code completion.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Custom operations 🚀
&lt;/h2&gt;

&lt;p&gt;What: builder methods annotated with &lt;code&gt;[&amp;lt;CustomOperation("myOperation")&amp;gt;]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Use cases: add new keywords, build a custom DSL. For example, the &lt;code&gt;query&lt;/code&gt; core CE supports &lt;code&gt;where&lt;/code&gt; and &lt;code&gt;select&lt;/code&gt; keywords like LINQ.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; you may need additional things that are not well documented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Additional properties for the &lt;code&gt;CustomOperation&lt;/code&gt; attribute:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AllowIntoPattern&lt;/code&gt;, &lt;code&gt;MaintainsVariableSpace&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IsLikeJoin&lt;/code&gt;, &lt;code&gt;IsLikeGroupJoin&lt;/code&gt;, &lt;code&gt;JoinConditionWord&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IsLikeZip&lt;/code&gt;...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Additional attributes on the method parameters, like &lt;code&gt;[&amp;lt;ProjectionParameter&amp;gt;]&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This topic would deserve a complete article. Still, you can find additional information here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/panesofglass/computation-expressions-workshop/blob/master/exercises/07_Queries.pdf" rel="noopener noreferrer"&gt;Computation Expressions Workshop: 7 - Query Expressions | GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf" rel="noopener noreferrer"&gt;The F# 4.1 Language Specification&lt;/a&gt;: search for &lt;code&gt;SimpleSequenceBuilder&lt;/code&gt; to get all the examples that show how the translation works between the CE body and the custom operations defined on the builder.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Let's review the pros and cons of computation expressions to get the full picture and make the appropriate decision about writing our own computation expression.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits ✅
&lt;/h3&gt;

&lt;p&gt;Computation expressions offer significant advantages for F# developers. They provide &lt;strong&gt;increased readability&lt;/strong&gt; through imperative-like code that feels natural while maintaining functional principles. They also &lt;strong&gt;reduce boilerplate&lt;/strong&gt; by hiding complex "machinery" behind clean, expressive syntax. Additionally, their &lt;strong&gt;extensibility&lt;/strong&gt; allows developers to extend existing CEs or even add the CE syntax support to any type. Finally, we can create &lt;strong&gt;domain-specific languages&lt;/strong&gt; (DSLs) to reify domain concepts through custom operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limits ⚠️
&lt;/h3&gt;

&lt;p&gt;However, computation expressions come with certain limitations that developers should be aware of. &lt;strong&gt;Compiler error messages&lt;/strong&gt; within CE bodies can often be cryptic and difficult to debug, making troubleshooting more challenging. &lt;strong&gt;Nesting different CEs&lt;/strong&gt; can make code more cumbersome to work with—for example, combining &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt; patterns. While custom combining CEs like &lt;code&gt;asyncResult&lt;/code&gt; in &lt;a href="https://demystifyfp.gitbook.io/fstoolkit-errorhandling/#a-motivating-example" rel="noopener noreferrer"&gt;FsToolkit&lt;/a&gt; offer alternatives, they add complexity. Finally, &lt;strong&gt;writing custom CEs can be challenging&lt;/strong&gt;, requiring developers to implement the right methods correctly and understand the underlying functional programming concepts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guidelines 📃
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Choose the main &lt;strong&gt;behaviour&lt;/strong&gt;: monoidal? monadic? applicative?

&lt;ul&gt;
&lt;li&gt;Prefer a single behaviour unless it's a generic/multi-purpose CE&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Create a &lt;strong&gt;builder&lt;/strong&gt; class&lt;/li&gt;

&lt;li&gt;Implement the main &lt;strong&gt;methods&lt;/strong&gt; to get the selected behaviour&lt;/li&gt;

&lt;li&gt;Use/Test your CE to verify it compiles &lt;em&gt;(see typical compilation errors below)&lt;/em&gt;, produces the expected result, and performs well.
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. This control construct may only be used if the computation expression builder defines a 'Delay' method
   =&amp;gt; Just implement the missing method in the builder.
2. Type constraint mismatch. The type ''b seq' is not compatible with type ''a list'
   =&amp;gt; Inspect the builder methods and track an inconsistency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tips 💡
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Get inspired by existing codebases that provide CEs - examples:

&lt;ul&gt;
&lt;li&gt;FSharpPlus → &lt;code&gt;monad&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;FsToolkit.ErrorHandling → &lt;code&gt;option&lt;/code&gt;, &lt;code&gt;result&lt;/code&gt;, &lt;code&gt;validation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/haf/expecto" rel="noopener noreferrer"&gt;Expecto&lt;/a&gt;: Testing library (&lt;code&gt;test "..." {...}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/compositionalit/farmer" rel="noopener noreferrer"&gt;Farmer&lt;/a&gt;: Infra as code for Azure (&lt;code&gt;storageAccount {...}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://saturnframework.org/" rel="noopener noreferrer"&gt;Saturn&lt;/a&gt;: Web framework on top of ASP.NET Core (&lt;code&gt;application {...}&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Overload methods to support more use cases like different input types

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Async&amp;lt;Result&amp;lt;_,_&amp;gt;&amp;gt;&lt;/code&gt; + &lt;code&gt;Async&amp;lt;_&amp;gt;&lt;/code&gt; + &lt;code&gt;Result&amp;lt;_,_&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Option&amp;lt;_&amp;gt;&lt;/code&gt; and &lt;code&gt;Nullable&amp;lt;_&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  🍔 Quiz
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Question 1: &lt;strong&gt;What is the primary purpose of computation expressions in F#?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; To replace all functional programming patterns&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; To provide imperative-like syntax for sequencing and combining computations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; To eliminate the need for type annotations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; To make F# code compatible with C#&lt;/p&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; To provide imperative-like syntax for sequencing and combining computations ✅&lt;/p&gt;



&lt;/p&gt;

&lt;h4&gt;
  
  
  Question 2: &lt;strong&gt;Which keywords identify a monadic computation expression?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; &lt;code&gt;yield&lt;/code&gt; and &lt;code&gt;yield!&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;and!&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; &lt;code&gt;do!&lt;/code&gt; and &lt;code&gt;while&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; &lt;code&gt;yield&lt;/code&gt; and &lt;code&gt;yield!&lt;/code&gt; keywords identify a monoidal CE ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt; keywords identify a monadic CE ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;and!&lt;/code&gt; keywords identify a applicative CE ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; &lt;code&gt;do!&lt;/code&gt; and &lt;code&gt;while&lt;/code&gt; keywords can be used with any kind of CE ❌&lt;/p&gt;



&lt;/p&gt;

&lt;h4&gt;
  
  
  Question 3: &lt;strong&gt;In a computation expression builder, what does the &lt;code&gt;Bind&lt;/code&gt; method correspond to?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; The &lt;code&gt;yield&lt;/code&gt; keyword&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; The &lt;code&gt;return&lt;/code&gt; keyword&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; The &lt;code&gt;let!&lt;/code&gt; keyword&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; The &lt;code&gt;else&lt;/code&gt; keyword when omitted&lt;/p&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; The &lt;code&gt;yield&lt;/code&gt; keyword corresponds to the &lt;code&gt;Yield&lt;/code&gt; method ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; The &lt;code&gt;return&lt;/code&gt; keyword corresponds to the &lt;code&gt;Return&lt;/code&gt; method ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; The &lt;code&gt;let!&lt;/code&gt; keyword corresponds to the &lt;code&gt;Bind&lt;/code&gt; method ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; The &lt;code&gt;else&lt;/code&gt; keyword, when omitted, corresponds to the &lt;code&gt;Zero&lt;/code&gt; method ❌&lt;/p&gt;



&lt;/p&gt;

&lt;h4&gt;
  
  
  Question 4: &lt;strong&gt;What is the signature of a typical monadic &lt;code&gt;Bind&lt;/code&gt; method?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; &lt;code&gt;M&amp;lt;T&amp;gt; -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; &lt;code&gt;T -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; &lt;code&gt;M&amp;lt;T&amp;gt; * (T -&amp;gt; M&amp;lt;U&amp;gt;) -&amp;gt; M&amp;lt;U&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; &lt;code&gt;M&amp;lt;T&amp;gt; * M&amp;lt;U&amp;gt; -&amp;gt; M&amp;lt;T * U&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;&lt;strong&gt;A.&lt;/strong&gt; &lt;code&gt;M&amp;lt;T&amp;gt; -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt; is the typical signature of &lt;code&gt;ReturnFrom&lt;/code&gt; and &lt;code&gt;YieldFrom&lt;/code&gt; methods ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.&lt;/strong&gt; &lt;code&gt;T -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt; is the typical signature of &lt;code&gt;Return&lt;/code&gt; and &lt;code&gt;Yield&lt;/code&gt; methods ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.&lt;/strong&gt; &lt;code&gt;M&amp;lt;T&amp;gt; * (T -&amp;gt; M&amp;lt;U&amp;gt;) -&amp;gt; M&amp;lt;U&amp;gt;&lt;/code&gt; is the typical signature of the &lt;code&gt;Bind&lt;/code&gt; method ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.&lt;/strong&gt; &lt;code&gt;M&amp;lt;T&amp;gt; * M&amp;lt;U&amp;gt; -&amp;gt; M&amp;lt;T * U&amp;gt;&lt;/code&gt; is the typical signature of &lt;code&gt;MergeSources&lt;/code&gt; method ❌&lt;/p&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/rdeneau/formation-fsharp/tree/main/src/FSharpTraining" rel="noopener noreferrer"&gt;Code examples in FSharpTraining.sln&lt;/a&gt; —Romain Deneau&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fsharpforfunandprofit.com/series/computation-expressions/" rel="noopener noreferrer"&gt;&lt;em&gt;The "Computation Expressions" series&lt;/em&gt;&lt;/a&gt; —F# for Fun and Profit&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions#creating-a-new-type-of-computation-expression" rel="noopener noreferrer"&gt;All CE methods | Learn F#&lt;/a&gt; —Microsoft&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/panesofglass/computation-expressions-workshop" rel="noopener noreferrer"&gt;Computation Expressions Workshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/computation-zoo.pdf" rel="noopener noreferrer"&gt;The F# Computation Expression Zoo&lt;/a&gt; —Tomas Petricek and Don Syme

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://tryjoinads.org/docs/computations/home.html" rel="noopener noreferrer"&gt;Documentation | Try Joinads&lt;/a&gt; —Tomas Petricek&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Extending F# through Computation Expressions: 📹 &lt;a href="https://youtu.be/bYor0oBgvws" rel="noopener noreferrer"&gt;Video&lt;/a&gt; • 📜 &lt;a href="https://panesofglass.github.io/computation-expressions/#/" rel="noopener noreferrer"&gt;Article&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>functional</category>
    </item>
    <item>
      <title>F# applicative computation expressions</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Fri, 22 Aug 2025 14:42:00 +0000</pubDate>
      <link>https://dev.to/rdeneau/f-applicative-computation-expressions-49l6</link>
      <guid>https://dev.to/rdeneau/f-applicative-computation-expressions-49l6</guid>
      <description>&lt;p&gt;This fifth article in the series dedicated to F# computation expressions is a guide to writing F# computation expressions (CE) with &lt;a href="https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7#applicative"&gt;applicative&lt;/a&gt; behavior.&lt;/p&gt;

&lt;p&gt;An applicative CE offers the widest variety of method combinations for the CE builder. We'll examine in detail when these are useful, based on compiler error messages and desugared versions of the expressions used in these tests.&lt;/p&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Builder method signatures&lt;/li&gt;
&lt;li&gt;
Applicative CE example: validation

&lt;ul&gt;
&lt;li&gt;Base implementation&lt;/li&gt;
&lt;li&gt;Use case: validate a customer&lt;/li&gt;
&lt;li&gt;Other method combinations&lt;/li&gt;
&lt;li&gt;FsToolkit validation CE&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Applicative CE example: async&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Applicative computation expressions are characterized by the use of the &lt;code&gt;and!&lt;/code&gt; keyword introduced in F# 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  Builder method signatures
&lt;/h2&gt;

&lt;p&gt;An applicative CE builder typically defines the following methods:&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;// Method        | Signature                        | Comment&lt;/span&gt;
    &lt;span class="nc"&gt;MergeSources&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&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;my&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&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;x&lt;/span&gt; &lt;span class="n"&gt;y&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;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt;
    &lt;span class="nc"&gt;BindReturn&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;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;(* ≡ *)&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;

&lt;span class="c1"&gt;// Additional methods for performance optimization&lt;/span&gt;
&lt;span class="c1"&gt;// - MergeSourcesN, N &amp;gt;= 3:&lt;/span&gt;
    &lt;span class="nc"&gt;MergeSources3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&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;my&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Y&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;mz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// - BindNReturn, N &amp;gt;= 2:&lt;/span&gt;
    &lt;span class="nc"&gt;Bind2Return&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&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;my&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Y&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;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;(* ≡ *)&lt;/span&gt; &lt;span class="n"&gt;map2&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt;
&lt;span class="c1"&gt;// - BindN, N &amp;gt;= 2:&lt;/span&gt;
    &lt;span class="nc"&gt;Bind2&lt;/span&gt;        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&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;my&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Y&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;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;Bind3&lt;/span&gt;        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;X&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;my&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Y&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;mz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Z&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;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Applicative CE example: validation
&lt;/h2&gt;

&lt;p&gt;The purpose is to accumulate errors given by a group of results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Base implementation
&lt;/h3&gt;

&lt;p&gt;The implementation relies on the type &lt;code&gt;Validation&amp;lt;'t, 'e&amp;gt;&lt;/code&gt; that is an alias of &lt;code&gt;Result&amp;lt;'t, 'e list&amp;gt;&lt;/code&gt;. The &lt;code&gt;Error&lt;/code&gt; case holds the list of accumulated errors.&lt;/p&gt;

&lt;p&gt;The builder implements two essential methods to achieve applicative behavior: &lt;code&gt;BindReturn&lt;/code&gt; and &lt;code&gt;MergeSources&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;type&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="kt"&gt;list&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;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;BindReturn&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;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Result&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;f&lt;/span&gt; &lt;span class="n"&gt;x&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;MergeSources&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;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;match&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;y&lt;/span&gt;&lt;span class="p"&gt;)&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;Ok&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;v2&lt;/span&gt;    &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// Merge both values in a pair&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e1&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;e2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Merge errors into a single list&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&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="o"&gt;_,&lt;/span&gt; &lt;span class="nc"&gt;Error&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="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;   &lt;span class="c1"&gt;// Short-circuit on single error source&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use case: validate a customer
&lt;/h3&gt;

&lt;p&gt;Let's create a &lt;a href="https://rdeneau.gitbook.io/fsharp-training/monadic-types/3-smart-constructor" rel="noopener noreferrer"&gt;smart constructor&lt;/a&gt; to get a valid customer: whose name is not null or empty, and whose height in centimeters is strictly positive. If both the name and height are invalid, we want to know both errors at once. This makes the use case ideal for the &lt;code&gt;validation {}&lt;/code&gt; computation expression with a &lt;code&gt;let! ... and! ...&lt;/code&gt; expression.&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="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Measure&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Name&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="nc"&gt;Height&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;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;&amp;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;validateHeight&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Height must be positive"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;validateName&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IsNullOrWhiteSpace&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Name can't be empty"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Customer&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;tryCreate&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Customer&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;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;validName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateName&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
            &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;validHeight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateHeight&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validHeight&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;c1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryCreate&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="c1"&gt;// Ok { Name = "Bob"; Height = 180 }&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryCreate&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// Error ["Height must be positive"]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;c3&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryCreate&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;    &lt;span class="c1"&gt;// Error ["Name can't be empty"; "Height must be positive"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desugaring:&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;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                                &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BindReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                            &lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MergeSources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateName&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt;          &lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="n"&gt;validateName&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateHeight&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&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;validateHeight&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                                            &lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Name&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;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;height&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;fun&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="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Name&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;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;})&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;h3&gt;
  
  
  Other method combinations
&lt;/h3&gt;

&lt;p&gt;Let's explore different method combinations to see what the compiler requires and how the expressions are desugared.&lt;/p&gt;

&lt;p&gt;For convenience, let's start by defining some helpers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Err&lt;/code&gt; active pattern simplifies pattern matching on &lt;code&gt;Validation&amp;lt;_, _&amp;gt;&lt;/code&gt; tuples, distinguishing between &lt;code&gt;Ok&lt;/code&gt; (all elements are valid) and &lt;code&gt;Error&lt;/code&gt; (any element is invalid). &lt;code&gt;Err&lt;/code&gt; is used in &lt;code&gt;bind2&lt;/code&gt; and &lt;code&gt;bind3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bind2&lt;/code&gt; and &lt;code&gt;bind3&lt;/code&gt; are the base helpers used to implement the builder methods that deal with two and three &lt;code&gt;Validation&amp;lt;_, _&amp;gt;&lt;/code&gt; parameters respectively.
&lt;/li&gt;
&lt;/ul&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="o"&gt;(|&lt;/span&gt;&lt;span class="nc"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;|)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&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;vx&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;Ok&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;Error&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Validation&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;ok&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nc"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;e&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;errors&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&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;Ok&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;Ok&lt;/span&gt; &lt;span class="n"&gt;y&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="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt; &lt;span class="n"&gt;ey&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;ey&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;bind3&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vz&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;Ok&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;Ok&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;z&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="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt; &lt;span class="n"&gt;ey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt; &lt;span class="n"&gt;ez&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;ey&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;ez&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Two-element expression
&lt;/h4&gt;

&lt;p&gt;To handle an expression like &lt;code&gt;let! ... and! ...&lt;/code&gt;, the combination of &lt;code&gt;Bind2&lt;/code&gt; and &lt;code&gt;Return&lt;/code&gt; is valid for the compiler:&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;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Bind2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="n"&gt;vy&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="n"&gt;y&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="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;y&lt;/span&gt;&lt;span class="o"&gt;))&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;Return&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&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;test_desugared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;10&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="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;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examining the desugared version, we see that this method combination is not more efficient than the classic &lt;code&gt;BindReturn&lt;/code&gt; and &lt;code&gt;MergeSources&lt;/code&gt; approach. Let's try using only &lt;code&gt;Bind2Return&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;type&lt;/span&gt; &lt;span class="nc"&gt;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Bind2Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="n"&gt;vy&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="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;y&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;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&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;test_desugared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind2Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;10&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="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;y&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&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;In this case, &lt;code&gt;Bind2Return&lt;/code&gt; can be the only method needed by the compiler. The desugared result confirms that it's the only method call, leading to a more efficient builder implementation for handling &lt;code&gt;let! ... and! ...&lt;/code&gt; expressions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Three-element expression
&lt;/h4&gt;

&lt;p&gt;The regular &lt;code&gt;BindReturn&lt;/code&gt; and &lt;code&gt;MergeSources&lt;/code&gt; method combination can handle an expression like &lt;code&gt;let! ... and! ... and! ...&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;type&lt;/span&gt; &lt;span class="nc"&gt;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;BindReturn&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;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Result&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;f&lt;/span&gt; &lt;span class="n"&gt;x&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;MergeSources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="n"&gt;vy&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="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&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;y&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;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&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="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&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;test_desugared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BindReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MergeSources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MergeSources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;))&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;z&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="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&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;The desugared version shows that two &lt;code&gt;MergeSources&lt;/code&gt; calls are needed to assemble the three values &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt; required for the final calculation &lt;code&gt;(z - x) * y&lt;/code&gt;. If the &lt;code&gt;MergeSources3&lt;/code&gt; method is provided, the compiler can replace this double call to &lt;code&gt;MergeSources&lt;/code&gt; with a single call to &lt;code&gt;MergeSources3&lt;/code&gt;, simplifying the parameter deconstruction to obtain &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt;—from &lt;code&gt;(x, (y, z))&lt;/code&gt; to &lt;code&gt;(x, y, z)&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;type&lt;/span&gt; &lt;span class="nc"&gt;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;BindReturn&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;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Result&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;f&lt;/span&gt; &lt;span class="n"&gt;x&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;MergeSources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="n"&gt;vy&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="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&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;y&lt;/span&gt;&lt;span class="o"&gt;))&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;MergeSources3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind3&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="n"&gt;vz&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="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&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;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&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="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&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;test_desugared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BindReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MergeSources3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&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;z&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="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&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;Note that &lt;code&gt;MergeSources&lt;/code&gt; is not used, but is still required for compilation 🤷&lt;/p&gt;

&lt;p&gt;Finally, we can verify that the locally optimal builder only needs a single method, &lt;code&gt;Bind3Return&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;type&lt;/span&gt; &lt;span class="nc"&gt;ValidationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Bind3Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;vz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&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="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind3&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="n"&gt;vz&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="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&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;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&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="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&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;test_desugared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind3Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="mi"&gt;3&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="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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&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;z&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="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&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;h4&gt;
  
  
  Method combination conclusion
&lt;/h4&gt;

&lt;p&gt;The regular &lt;code&gt;BindReturn&lt;/code&gt; and &lt;code&gt;MergeSources&lt;/code&gt; method combination can handle all cases, but requires one additional call to &lt;code&gt;MergeSources&lt;/code&gt; per additional input value. You can optimize the number of builder method calls by providing additional builder methods. &lt;code&gt;BindNReturn&lt;/code&gt; methods are the most efficient option. &lt;code&gt;MergeSourcesN&lt;/code&gt; methods are less efficient but more versatile, as they can be combined to handle tuples with more elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  FsToolkit validation CE
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/demystifyfp/FsToolkit.ErrorHandling/" rel="noopener noreferrer"&gt;FsToolkit.ErrorHandling&lt;/a&gt; provides a similar &lt;code&gt;validation {}&lt;/code&gt; implementation.&lt;/p&gt;

&lt;p&gt;The desugaring reveals the definition of additional methods: &lt;code&gt;Delay&lt;/code&gt;, &lt;code&gt;Run&lt;/code&gt;, &lt;code&gt;Source&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="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                                &lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateName&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt;          &lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateHeight&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&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;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BindReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Name&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;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MergeSources&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;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validateName&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                                            &lt;span class="p"&gt;;&lt;/span&gt;                  &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validateHeight&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;
                                            &lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="o"&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;fun&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="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Name&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;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;})&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="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;h4&gt;
  
  
  &lt;code&gt;Source&lt;/code&gt; methods
&lt;/h4&gt;

&lt;p&gt;In FsToolkit's &lt;code&gt;validation {}&lt;/code&gt;, there are a couple of &lt;code&gt;Source&lt;/code&gt; methods defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The main definition is the &lt;code&gt;id&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Another overload is interesting: it converts a &lt;code&gt;Result&amp;lt;'a, 'e&amp;gt;&lt;/code&gt; into a &lt;code&gt;Validation&amp;lt;'a, 'e&amp;gt;&lt;/code&gt;. Because it's defined as an extension method, it has lower priority for the compiler, which improves type inference. Otherwise, type annotations would be required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;☝️ &lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;Source&lt;/code&gt; documentation is scarce. The most valuable information comes from a &lt;a href="https://stackoverflow.com/a/35301315/8634147" rel="noopener noreferrer"&gt;Stack Overflow question&lt;/a&gt; referenced in the FsToolkit source code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Applicative CE example: async
&lt;/h2&gt;

&lt;p&gt;As of today, we have to use intermediary calls to &lt;code&gt;Async.StartChild&lt;/code&gt; to get the tasks executed in parallel. This feature can be implemented as an applicative behavior behind the &lt;code&gt;let! ... and and! ...&lt;/code&gt; syntax. Let's extend the &lt;code&gt;AsyncBuilder&lt;/code&gt; class to support this feature.&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="nc"&gt;Async&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;bind2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&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;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&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;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt; &lt;span class="p"&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;StartChild&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt; &lt;span class="p"&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;StartChild&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;ry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt; &lt;span class="n"&gt;ry&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;bind3&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&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;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&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;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt; &lt;span class="p"&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;StartChild&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt; &lt;span class="p"&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;StartChild&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;cz&lt;/span&gt; &lt;span class="p"&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;StartChild&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;ry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;rz&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cz&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt; &lt;span class="n"&gt;ry&lt;/span&gt; &lt;span class="n"&gt;rz&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;AsyncBuilder&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;Bind2Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&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="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="n"&gt;ty&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="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;})&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;Bind3Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&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="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind3&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt; &lt;span class="n"&gt;tz&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="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;})&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;MergeSources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&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="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind2&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="n"&gt;ty&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="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&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;y&lt;/span&gt; &lt;span class="o"&gt;})&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;MergeSources3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&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="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind3&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt; &lt;span class="n"&gt;tz&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="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The calls to &lt;code&gt;Async.StartChild&lt;/code&gt; are done in &lt;code&gt;Async.bind2&lt;/code&gt;. We provide an &lt;code&gt;Async.bind3&lt;/code&gt; to optimize the usage up to three parallel asynchronous tasks.&lt;/p&gt;

&lt;p&gt;Let's test this by comparing the execution duration of three tasks run in series versus in parallel:&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;open&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Swensen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Unquote&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;Xunit&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TimeSpan&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;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&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;Sleep&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&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;Take&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;LessThan&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;TimeSpan&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;MoreThan&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;TimeSpan&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;takes&lt;/span&gt; &lt;span class="n"&gt;task&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;sw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Diagnostics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StartNew&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&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="n"&gt;task&lt;/span&gt;
    &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Stop&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;actualTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Elapsed&lt;/span&gt;

    &lt;span class="n"&gt;test&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;@&lt;/span&gt;
            &lt;span class="n"&gt;takes&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;forall&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;function&lt;/span&gt;
                &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LessThan&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;actualTime&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
                &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MoreThan&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;actualTime&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;@&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Fact&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;``Should run the tasks in series``&lt;/span&gt; &lt;span class="bp"&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;taskInSeries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&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;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&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;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;taskInSeries&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nn"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MoreThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;40&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;lt;&lt;/span&gt;&lt;span class="nc"&gt;Fact&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;``Should run the 3 tasks in parallel``&lt;/span&gt; &lt;span class="bp"&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;tasksInParallel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&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;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&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;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;returnAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;tasksInParallel&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nn"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MoreThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="nn"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LessThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FromMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;40&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Applicative computation expressions in F# enable parallel computation and error accumulation using the &lt;code&gt;and!&lt;/code&gt; syntax introduced in F# 5. By implementing &lt;code&gt;MergeSources&lt;/code&gt; and &lt;code&gt;BindReturn&lt;/code&gt; methods, you can create powerful validation workflows that collect all errors instead of stopping at the first failure, as well as efficient computations that leverage parallelism. This approach is particularly valuable for form validation, configuration parsing, and any scenario where you want to provide comprehensive feedback to users about multiple validation failures simultaneously. While applicative computation expressions are less versatile than monadic ones, they excel in specific scenarios where their unique capabilities make a significant difference.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>functional</category>
    </item>
    <item>
      <title>F# monadic computation expressions</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Fri, 22 Aug 2025 14:23:00 +0000</pubDate>
      <link>https://dev.to/rdeneau/f-monadic-computation-expressions-4n0i</link>
      <guid>https://dev.to/rdeneau/f-monadic-computation-expressions-4n0i</guid>
      <description>&lt;p&gt;This fourth article in the series dedicated to F# computation expressions is a guide to writing F# computation expressions having a &lt;a href="https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7#monad"&gt;monadic&lt;/a&gt; behavior.&lt;/p&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Builder method signatures

&lt;ul&gt;
&lt;li&gt;Monadic &lt;em&gt;vs&lt;/em&gt; Monoidal&lt;/li&gt;
&lt;li&gt;CE monadic and delayed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
CE monadic examples

&lt;ul&gt;
&lt;li&gt;CE monadic example - &lt;code&gt;result {}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;CE monadic: FSharpPlus &lt;code&gt;monad {}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Monad stack, monad transformers

&lt;ul&gt;
&lt;li&gt;1. Academic style (with FSharpPlus)&lt;/li&gt;
&lt;li&gt;2. Idiomatic style&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A monadic CE can be identified by the usage of &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt; keywords, revealing the monadic &lt;code&gt;bind&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt; operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Builder method signatures
&lt;/h2&gt;

&lt;p&gt;Behind the scenes, builders of these CEs should/can implement these methods:&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;// Method     | Signature                                     | CE syntax supported&lt;/span&gt;
    &lt;span class="nc"&gt;Bind&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&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;xs&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
                &lt;span class="c"&gt;(* when T = unit *)&lt;/span&gt;                           &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
    &lt;span class="nc"&gt;Return&lt;/span&gt;    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                                     &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="nc"&gt;ReturnFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                                  &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="c1"&gt;// Additional methods&lt;/span&gt;
    &lt;span class="nc"&gt;Zero&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                                  &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="c1"&gt;// without `else` // Typically `unit -&amp;gt; M&amp;lt;unit&amp;gt;`&lt;/span&gt;
    &lt;span class="nc"&gt;Combine&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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;e1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;e2&lt;/span&gt;  &lt;span class="c1"&gt;// e.g. one loop followed by another one&lt;/span&gt;
    &lt;span class="nc"&gt;TryWith&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;exn&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="nc"&gt;TryFinally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;              &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;
    &lt;span class="nc"&gt;While&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&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="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;
    &lt;span class="nc"&gt;For&lt;/span&gt;       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;            &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="nc"&gt;Using&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IDisposable&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="o"&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;xs&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Monadic &lt;em&gt;vs&lt;/em&gt; Monoidal
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Return&lt;/code&gt; (monadic) &lt;em&gt;vs&lt;/em&gt; &lt;code&gt;Yield&lt;/code&gt; (monoidal)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Same signature: &lt;code&gt;T -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A series of &lt;code&gt;return&lt;/code&gt; is not expected
→ Monadic &lt;code&gt;Combine&lt;/code&gt; takes only a monadic command &lt;code&gt;M&amp;lt;unit&amp;gt;&lt;/code&gt; as 1st param&lt;/li&gt;
&lt;li&gt;CE enforces appropriate syntax by implementing one of these methods:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;seq {}&lt;/code&gt; allows &lt;code&gt;yield&lt;/code&gt; but not &lt;code&gt;return&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;async {}&lt;/code&gt;: the reverse&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;For&lt;/code&gt; and &lt;code&gt;While&lt;/code&gt;
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th width="99"&gt;Method&lt;/th&gt;
&lt;th width="147"&gt;CE&lt;/th&gt;
&lt;th&gt;Signature&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;For&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Monoidal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;seq&amp;lt;T&amp;gt; * (T -&amp;gt; M&amp;lt;U&amp;gt;) -&amp;gt; M&amp;lt;U&amp;gt; or seq&amp;lt;M&amp;lt;U&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Monadic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;seq&amp;lt;T&amp;gt; * (T -&amp;gt; M&amp;lt;unit&amp;gt;) -&amp;gt; M&amp;lt;unit&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;While&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Monoidal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(unit -&amp;gt; bool) * Delayed&amp;lt;T&amp;gt; -&amp;gt; M&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Monadic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(unit -&amp;gt; bool) * (unit -&amp;gt; M&amp;lt;unit&amp;gt;) -&amp;gt; M&amp;lt;unit&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;👉 Different use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monoidal: Comprehension syntax&lt;/li&gt;
&lt;li&gt;Monadic: Series of effectful commands&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CE monadic and delayed
&lt;/h3&gt;

&lt;p&gt;Like monoidal CE, monadic CE can use a &lt;code&gt;Delayed&amp;lt;'t&amp;gt;&lt;/code&gt; type.&lt;br&gt;
→ Impacts on the method signatures:&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;Delay&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;thunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;Run&lt;/span&gt;        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;Combine&lt;/span&gt;    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;While&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;TryFinally&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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;finalizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;TryWith&lt;/span&gt;    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exn&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CE monadic examples
&lt;/h2&gt;

&lt;p&gt;☝️ The initial CEs studied—&lt;code&gt;logger {}&lt;/code&gt; and &lt;code&gt;option {}&lt;/code&gt;—were monadic.&lt;/p&gt;

&lt;h3&gt;
  
  
  CE monadic example - &lt;code&gt;result {}&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let's build a &lt;code&gt;result {}&lt;/code&gt; CE to play with dice!&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;ResultBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt; &lt;span class="n"&gt;f&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;Return&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="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;x&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;ReturnFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ResultBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// ---&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rollDice&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;random&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NewGuid&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetHashCode&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Next&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="mi"&gt;7&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;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;dice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rollDice&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dice&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;"Not the expected dice {dice}."&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;tryGetAPairOf6&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;result&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;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desugaring:&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;tryGetAPairOf6&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;result&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;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&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;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;    &lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;n&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="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;    &lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tryGetDice&lt;/span&gt; &lt;span class="n"&gt;n&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="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;         &lt;span class="p"&gt;;&lt;/span&gt;            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;true&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="o"&gt;))&lt;/span&gt;
                            &lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CE monadic: FSharpPlus &lt;code&gt;monad {}&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://fsprojects.github.io/FSharpPlus/computation-expressions.html" rel="noopener noreferrer"&gt;FSharpPlus&lt;/a&gt; provides a &lt;code&gt;monad&lt;/code&gt; CE&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works for all monadic types: &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;, ... and even &lt;code&gt;Lazy&lt;/code&gt; 🎉&lt;/li&gt;
&lt;li&gt;Supports monad stacks with monad transformers 📍&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Limits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confusing: the &lt;code&gt;monad&lt;/code&gt; CE has 4 flavours to cover all cases: delayed or strict, embedded side-effects or not&lt;/li&gt;
&lt;li&gt;Based on SRTP: can be very long to compile!&lt;/li&gt;
&lt;li&gt;Documentation not exhaustive, relying on Haskell knowledges&lt;/li&gt;
&lt;li&gt;Very Haskell-oriented: not idiomatic F#&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monad stack, monad transformers
&lt;/h2&gt;

&lt;p&gt;A monad stack is a composition of different monads.&lt;br&gt;
→ Example: &lt;code&gt;Async&lt;/code&gt;+&lt;code&gt;Option&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can handle it with 2 styles: academic or F# idiomatic.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Academic style (with FSharpPlus)
&lt;/h3&gt;

&lt;p&gt;Monad transformer (here &lt;code&gt;MaybeT&lt;/code&gt;)&lt;br&gt;
→ Extends &lt;code&gt;Async&lt;/code&gt; to handle both effects&lt;br&gt;
→ Resulting type: &lt;code&gt;MaybeT&amp;lt;Async&amp;lt;'t&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;✅ Reusable with other inner monads&lt;br&gt;
❌ Less easy to evaluate the resulting value&lt;br&gt;
❌ Not idiomatic&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Idiomatic style
&lt;/h3&gt;

&lt;p&gt;Custom CE &lt;code&gt;asyncOption&lt;/code&gt;, based on the &lt;code&gt;async&lt;/code&gt; CE, handling the &lt;code&gt;Async&amp;lt;Option&amp;lt;'t&amp;gt;&amp;gt;&lt;/code&gt; type&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;AsyncOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// Convenient alias, not required&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;AsyncOptionBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aoX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AsyncOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;AsyncOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AsyncOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;b&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;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;aoX&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;x&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;f&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;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&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;member&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Return&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="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AsyncOption&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&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;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Some&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;⚠️ Limits: Not reusable, just copiable for &lt;code&gt;asyncResult&lt;/code&gt;, for instance&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Monadic computation expressions in F# provide a familiar syntax—based on &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt; keywords—for sequencing effectful computations. While you can build custom monadic CEs for specific domain needs or leverage libraries like FSharpPlus for academic-style programming, the most practical approach is often creating idiomatic F# builders tailored to your specific monad combinations, such as &lt;code&gt;Async&amp;lt;Option&amp;lt;'t&amp;gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;Async&amp;lt;Result&amp;lt;'t, 'e&amp;gt;&amp;gt;&lt;/code&gt;. This strikes the right balance between expressiveness and maintainability in typical F# codebases.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>functional</category>
    </item>
    <item>
      <title>F# monoidal computation expressions</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Fri, 22 Aug 2025 13:50:00 +0000</pubDate>
      <link>https://dev.to/rdeneau/f-monoidal-computation-expressions-2l06</link>
      <guid>https://dev.to/rdeneau/f-monoidal-computation-expressions-2l06</guid>
      <description>&lt;p&gt;This third article in the series dedicated to F# computation expressions is a guide to writing F# computation expressions having a &lt;a href="https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7#monoid"&gt;monoidal&lt;/a&gt; behavior.&lt;/p&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Builder method signatures&lt;/li&gt;
&lt;li&gt;
CE monoidal &lt;em&gt;vs&lt;/em&gt; comprehension

&lt;ul&gt;
&lt;li&gt;Comprehension definition&lt;/li&gt;
&lt;li&gt;Comparison&lt;/li&gt;
&lt;li&gt;Minimal set of methods expected for each&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
CE monoidal example: &lt;code&gt;multiplication {}&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Exercise&lt;/li&gt;
&lt;li&gt;Desugaring&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;
CE monoidal kinds

&lt;ul&gt;
&lt;li&gt;CE monoidal to generate a collection&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A monoidal CE can be identified by the usage of &lt;code&gt;yield&lt;/code&gt; and &lt;code&gt;yield!&lt;/code&gt; keywords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relationship with the monoid:&lt;/strong&gt;&lt;br&gt;
→ Hidden in the builder methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;+&lt;/code&gt; operation → &lt;code&gt;Combine&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;e&lt;/code&gt; neutral element → &lt;code&gt;Zero&lt;/code&gt; method&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Builder method signatures
&lt;/h2&gt;

&lt;p&gt;Like we did for functional patterns, we use the generic type notation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt;: type returned by the CE&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt;: presented later 📍
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Method     | Signature                           | CE syntax supported&lt;/span&gt;
    &lt;span class="nc"&gt;Yield&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;x&lt;/span&gt;
    &lt;span class="nc"&gt;YieldFrom&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
    &lt;span class="nc"&gt;Zero&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="c1"&gt;// without `else`  // Monoid neutral element&lt;/span&gt;
    &lt;span class="nc"&gt;Combine&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                                   &lt;span class="c1"&gt;// Monoid + operation&lt;/span&gt;
    &lt;span class="nc"&gt;Delay&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// always required with Combine&lt;/span&gt;

&lt;span class="c1"&gt;// Other additional methods&lt;/span&gt;
    &lt;span class="nc"&gt;Run&lt;/span&gt;       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;For&lt;/span&gt;       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
                              &lt;span class="c"&gt;(* or *)&lt;/span&gt;  &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;While&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="nc"&gt;TryWith&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;exn&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;       &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="nc"&gt;TryFinally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  CE monoidal &lt;em&gt;vs&lt;/em&gt; comprehension
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Comprehension definition
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;It is the concise and declarative syntax to build collections with control flow keywords &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;... and ranges &lt;code&gt;start..end&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Similar syntax from caller perspective&lt;/li&gt;
&lt;li&gt;Distinct overlapping concepts&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Minimal set of methods expected for each
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Monoidal CE: &lt;code&gt;Yield&lt;/code&gt;, &lt;code&gt;Combine&lt;/code&gt;, &lt;code&gt;Zero&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Comprehension: &lt;code&gt;For&lt;/code&gt;, &lt;code&gt;Yield&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  CE monoidal example: &lt;code&gt;multiplication {}&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let's build a CE that multiplies the integers yielded in the computation body:&lt;br&gt;
→ CE type: &lt;code&gt;M&amp;lt;T&amp;gt; = int&lt;/code&gt; • Monoid operation = &lt;code&gt;*&lt;/code&gt; • Neutral element = &lt;code&gt;1&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;type&lt;/span&gt; &lt;span class="nc"&gt;MultiplicationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&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;member&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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;Combine&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;y&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;y&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;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// eager evaluation&lt;/span&gt;

    &lt;span class="k"&gt;member&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;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xs&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;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fold&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;res&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;x&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;multiplication&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MultiplicationBuilder&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;shouldBe10&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;multiplication&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="mi"&gt;2&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;factorialOf5&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;multiplication&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&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;-&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="c1"&gt;// 2 * 3 * 4 * 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exercise
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Copy this snippet in vs code&lt;/li&gt;
&lt;li&gt;Comment out builder methods

&lt;ul&gt;
&lt;li&gt;To start with an empty builder, add this line &lt;code&gt;let _ = ()&lt;/code&gt; in the body.&lt;/li&gt;
&lt;li&gt;After adding the first method, this line can be removed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Let the compiler errors in &lt;code&gt;shouldBe10&lt;/code&gt; and &lt;code&gt;factorialOf5&lt;/code&gt; guide you to add the relevant methods.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Desugaring
&lt;/h3&gt;

&lt;p&gt;Desugared &lt;code&gt;multiplication { yield 5; yield 2 }&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="c1"&gt;// Original&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;shouldBe10&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Simplified (without Delay)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;shouldBe10&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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;Desugared &lt;code&gt;multiplication { for i in 2..5 -&amp;gt; i }&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="c1"&gt;// Original&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;factorialOf5&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delay&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;For&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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="n"&gt;arg2&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;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Simplified&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;factorialOf5&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;For&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="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;multiplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; represents a delayed computation and is used in these methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Delay&lt;/code&gt; returns this type, hence defines it for the CE&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Combine&lt;/code&gt;, &lt;code&gt;Run&lt;/code&gt;, &lt;code&gt;While&lt;/code&gt; and &lt;code&gt;TryFinally&lt;/code&gt; used it as input parameter
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt; &lt;span class="nc"&gt;Delay&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;thunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;Combine&lt;/span&gt;    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;Run&lt;/span&gt;        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;While&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nc"&gt;TryFinally&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Delayed&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&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;finalizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Delay&lt;/code&gt; is required by the presence of &lt;code&gt;Combine&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Delay&lt;/code&gt; is called each time converting from &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt; to &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; is needed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; is internal to the CE.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Run&lt;/code&gt; is required at the end to get back the &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;... &lt;strong&gt;only&lt;/strong&gt; when &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; ≠ &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt;, otherwise it can be omitted.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;👉 Enables to implement &lt;strong&gt;laziness and short-circuiting&lt;/strong&gt; at the CE level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; lazy &lt;code&gt;multiplication {}&lt;/code&gt; with &lt;code&gt;Combine&lt;/code&gt; optimized when &lt;code&gt;x = 0&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;type&lt;/span&gt; &lt;span class="nc"&gt;MultiplicationBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&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;member&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Yield&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;thunk&lt;/span&gt; &lt;span class="c1"&gt;// Lazy evaluation&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;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delayedX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;delayedX&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Required to get a final `int`&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;Combine&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="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delayedY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;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="kt"&gt;int&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;x&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// 👈 Short-circuit for multiplication by zero&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="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;delayedY&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xs&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;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fold&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;res&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&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;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&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="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Difference&lt;/th&gt;
&lt;th&gt;Eager&lt;/th&gt;
&lt;th&gt;Lazy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Delay&lt;/code&gt; return type&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;unit -&amp;gt; int&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Omitted&lt;/td&gt;
&lt;td&gt;Required to get back an &lt;code&gt;int&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Combine&lt;/code&gt; 2nd parameter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;unit -&amp;gt; int&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;For&lt;/code&gt; calling &lt;code&gt;Delay&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Omitted&lt;/td&gt;
&lt;td&gt;Explicit but not required here&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39dx3tm50mxhft9r9y8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39dx3tm50mxhft9r9y8q.png" alt="Differences between the eager and the lazy implementation of the multiplication CE"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CE monoidal kinds
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;multiplication {}&lt;/code&gt;, we've seen a first kind of monoidal CE:&lt;br&gt;
→ To reduce multiple yielded values into 1.&lt;/p&gt;

&lt;p&gt;There is a second kind of monoidal CE:&lt;br&gt;
→ To aggregate multiple yielded values into a collection.&lt;br&gt;
→ Example: &lt;code&gt;seq {}&lt;/code&gt; returns a &lt;code&gt;'t seq&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  CE monoidal to generate a collection
&lt;/h3&gt;

&lt;p&gt;Let's build a &lt;code&gt;list {}&lt;/code&gt; monoidal CE!&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;ListBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Zero&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;// List.empty&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;Yield&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="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="c1"&gt;// List.singleton&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;YieldFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xs&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;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thunk&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// eager evaluation&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;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt; &lt;span class="c1"&gt;// List.append&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;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&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="nn"&gt;Seq&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="kt"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ListBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt; is &lt;code&gt;'t list&lt;/code&gt; → type returned by &lt;code&gt;Yield&lt;/code&gt; and &lt;code&gt;Zero&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;For&lt;/code&gt; uses an intermediary sequence to collect the values returned by &lt;code&gt;f&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's test the CE to generate the list &lt;code&gt;[begin; 16; 9; 4; 1; 2; 4; 6; 8; end]&lt;/code&gt;&lt;br&gt;
&lt;em&gt;(Desugared code simplified)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft963gf9k2qzv6cno6zey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft963gf9k2qzv6cno6zey.png" alt="list {} CE desugared"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comparison with the same expression in a list comprehension:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9gksnrzmac3nciwhg6y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9gksnrzmac3nciwhg6y.png" alt="List comprehension desugared"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;list { expr }&lt;/code&gt; &lt;em&gt;vs&lt;/em&gt; &lt;code&gt;[ expr ]&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[ expr ]&lt;/code&gt; uses a hidden &lt;code&gt;seq&lt;/code&gt; all through the computation and ends with a &lt;code&gt;toList&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;All methods are inlined:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;&lt;code&gt;list { expr }&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;[ expr ]&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Combine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xs @ ys =&amp;gt; List.append&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.append&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Yield&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[x] =&amp;gt; List.singleton&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.singleton&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Zero&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[] =&amp;gt; List.empty&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.empty&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;For&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Seq.collect&lt;/code&gt; &amp;amp; &lt;code&gt;Seq.toList&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.collect&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Monoidal computation expressions provide an elegant and powerful syntax for combining and aggregating values in F#. By implementing a builder with just a few key methods—&lt;code&gt;Combine&lt;/code&gt; and &lt;code&gt;Zero&lt;/code&gt; which correspond to the monoid's &lt;code&gt;+&lt;/code&gt; operation and &lt;code&gt;e&lt;/code&gt; neutral element, alongside &lt;code&gt;Yield&lt;/code&gt;, &lt;code&gt;YieldFrom&lt;/code&gt;, and &lt;code&gt;For&lt;/code&gt; methods to support comprehension syntax—you can either reduce values to a single result (similar to the &lt;em&gt;Composite&lt;/em&gt; design pattern) or build collections with natural, imperative-like code. Additionally, leveraging the &lt;code&gt;Delayed&amp;lt;T&amp;gt;&lt;/code&gt; type enables optimization opportunities for both behavior and performance within your computation expressions.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>functional</category>
    </item>
    <item>
      <title>Functional patterns for F# computation expressions</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Fri, 22 Aug 2025 13:10:00 +0000</pubDate>
      <link>https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7</link>
      <guid>https://dev.to/rdeneau/functional-patterns-for-f-computation-expressions-46c7</guid>
      <description>&lt;p&gt;This second article in the series dedicated to F# computation expressions is an introduction to functional patterns for F# developers who wish to write or maintain computation expressions, i.e., applicative, functor, monad, and monoid.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;☝️ &lt;strong&gt;Note:&lt;/strong&gt; There are more functional patterns coming from category theory, but they are out of scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;
Introduction

&lt;ul&gt;
&lt;li&gt;F# and functional patterns&lt;/li&gt;
&lt;li&gt;General definition&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Monoid

&lt;ul&gt;
&lt;li&gt;Monoid laws&lt;/li&gt;
&lt;li&gt;Monoid examples&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Functor

&lt;ul&gt;
&lt;li&gt;Functor definition&lt;/li&gt;
&lt;li&gt;Functor laws&lt;/li&gt;
&lt;li&gt;Functor examples&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Monad

&lt;ul&gt;
&lt;li&gt;Monad definition&lt;/li&gt;
&lt;li&gt;Monad laws&lt;/li&gt;
&lt;li&gt;Monad examples&lt;/li&gt;
&lt;li&gt;Monad &lt;em&gt;vs&lt;/em&gt; Functor&lt;/li&gt;
&lt;li&gt;Monad alternative definition&lt;/li&gt;
&lt;li&gt;Regular functions &lt;em&gt;vs&lt;/em&gt; monadic functions&lt;/li&gt;
&lt;li&gt;Monads &lt;em&gt;vs&lt;/em&gt; Effects&lt;/li&gt;
&lt;li&gt;Other common monads&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Applicative (Functor)

&lt;ul&gt;
&lt;li&gt;Applicative definition&lt;/li&gt;
&lt;li&gt;Applicative laws&lt;/li&gt;
&lt;li&gt;Applicative &lt;em&gt;vs&lt;/em&gt; Functor&lt;/li&gt;
&lt;li&gt;Applicative &lt;em&gt;vs&lt;/em&gt; Monad&lt;/li&gt;
&lt;li&gt;Applicative: multi-param curried function&lt;/li&gt;
&lt;li&gt;Applicative styles&lt;/li&gt;
&lt;li&gt;Applicative &lt;em&gt;vs&lt;/em&gt; Monadic behaviour&lt;/li&gt;
&lt;li&gt;Applicative parallel behaviour&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Wrap up

&lt;ul&gt;
&lt;li&gt;Functional patterns key points&lt;/li&gt;
&lt;li&gt;Functional patterns in F# language&lt;/li&gt;
&lt;li&gt;Additional resources 🔗&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  F# and functional patterns
&lt;/h3&gt;

&lt;p&gt;Unlike other strongly typed programming languages such as Haskell, OCaml and Scala, these functional patterns are not necessarily useful for writing code in F#. Indeed, Don Syme designed the language to be easily accessible, in order to reach a wider audience of developers and avoid too big a gap with other .NET languages, particularly C#, its flagship language. However, these patterns are an integral part of the F# language, without necessarily being realized. But if you want to understand the different kinds of computation expressions, these patterns are very useful.&lt;/p&gt;

&lt;p&gt;F# uses these functional patterns under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; are monadic types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Async&lt;/code&gt; is monadic too&lt;/li&gt;
&lt;li&gt;Collection types &lt;code&gt;Array&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt; and &lt;code&gt;Seq&lt;/code&gt; are both monadic and monoidal types!&lt;/li&gt;
&lt;li&gt;Computation expressions can be monadic or applicative or monoidal&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General definition
&lt;/h3&gt;

&lt;p&gt;In F#, the functional patterns consist of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A type&lt;/li&gt;
&lt;li&gt;1 or 2 operations on this type&lt;/li&gt;
&lt;li&gt;A possible special instance of this type&lt;/li&gt;
&lt;li&gt;Some laws constraining/shaping the whole&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The type is generally noted &lt;code&gt;M&amp;lt;'T&amp;gt;&lt;/code&gt;, where &lt;code&gt;M&lt;/code&gt; is a &lt;em&gt;generic type&lt;/em&gt; and &lt;code&gt;'T&lt;/code&gt; its type parameter referring to the type of elements that can be contained in &lt;code&gt;M&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monoid
&lt;/h2&gt;

&lt;p&gt;Etymology (Greek): &lt;code&gt;monos&lt;/code&gt; &lt;em&gt;(single, unique)&lt;/em&gt; • &lt;code&gt;eidos&lt;/code&gt; &lt;em&gt;(form, appearance)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;≃ Type &lt;code&gt;T&lt;/code&gt; defining a set with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binary operation &lt;code&gt;+&lt;/code&gt;: &lt;code&gt;T -&amp;gt; T -&amp;gt; T&lt;/code&gt;
→ To &lt;em&gt;combine&lt;/em&gt; 2 elements into 1&lt;/li&gt;
&lt;li&gt;Neutral element &lt;code&gt;e&lt;/code&gt; (a.k.a. &lt;em&gt;identity&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monoid laws
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Associativity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;+&lt;/code&gt; is associative&lt;br&gt;
→ &lt;code&gt;a + (b + c)&lt;/code&gt; ≡ &lt;code&gt;(a + b) + c&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. &lt;strong&gt;Identity Element&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;e&lt;/code&gt; is combinable with any instance &lt;code&gt;a&lt;/code&gt; of &lt;code&gt;T&lt;/code&gt; without effect&lt;br&gt;
→ &lt;code&gt;a + e&lt;/code&gt; ≡ &lt;code&gt;e + a&lt;/code&gt; ≡ &lt;code&gt;a&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Monoid examples
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th width="116"&gt;Type&lt;/th&gt;
&lt;th width="165"&gt;Operator&lt;/th&gt;
&lt;th width="213"&gt;Identity&lt;/th&gt;
&lt;th&gt;Law 2&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;+&lt;/code&gt; &lt;em&gt;(add)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i + 0 = 0 + i = i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;*&lt;/code&gt; &lt;em&gt;(multiply)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i * 1 = 1 * i = i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;+&lt;/code&gt; &lt;em&gt;(concat)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;""&lt;/code&gt; &lt;em&gt;(empty string)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s + "" = "" + s = s&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;'a list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@&lt;/code&gt; (&lt;code&gt;List.append&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[]&lt;/code&gt; &lt;em&gt;(empty list)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;l @ [] = [] @ l = l&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Functions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; &lt;em&gt;(compose)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;id&lt;/code&gt; (&lt;code&gt;fun x -&amp;gt; x&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;f &amp;gt;&amp;gt; id = id &amp;gt;&amp;gt; f = f&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; The monoid is a generalization of the &lt;strong&gt;Composite&lt;/strong&gt; &lt;em&gt;OO design pattern&lt;/em&gt; - see &lt;br&gt;
&lt;a href="https://blog.ploeh.dk/2018/03/12/composite-as-a-monoid/" rel="noopener noreferrer"&gt;Composite as a monoid&lt;/a&gt; &lt;em&gt;by Mark Seemann&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Functor
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Functor definition
&lt;/h3&gt;

&lt;p&gt;≃ Any generic type, noted &lt;code&gt;F&amp;lt;'T&amp;gt;&lt;/code&gt;, with a &lt;code&gt;map&lt;/code&gt; operation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signature: &lt;code&gt;map: (f: 'T -&amp;gt; 'U) -&amp;gt; F&amp;lt;'T&amp;gt; -&amp;gt; F&amp;lt;'U&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;map&lt;/code&gt; preserves the structure: e.g. mapping a &lt;code&gt;List&lt;/code&gt; returns another &lt;code&gt;List&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Functor laws
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Law 1 - &lt;strong&gt;Identity law&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Mapping the &lt;code&gt;id&lt;/code&gt; function over a Functor &lt;code&gt;F&lt;/code&gt; should not change &lt;code&gt;F&lt;/code&gt;.&lt;br&gt;
→ &lt;code&gt;map id F&lt;/code&gt; ≡ &lt;code&gt;F&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Law 2 - &lt;strong&gt;Composition law&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Mapping the composition of 2 functions &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;g&lt;/code&gt; is the same as mapping &lt;code&gt;f&lt;/code&gt; and then mapping &lt;code&gt;g&lt;/code&gt; over the result.&lt;br&gt;
→ &lt;code&gt;map (f &amp;gt;&amp;gt; g)&lt;/code&gt; ≡ &lt;code&gt;map f &amp;gt;&amp;gt; map g&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Functor examples
&lt;/h3&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;Map&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Option&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Option.map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Result&amp;lt;'T, _&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Result.map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;List&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;List.map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Array&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Array.map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Seq&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Async&amp;lt;'T&amp;gt;&lt;/code&gt; too, but through the &lt;code&gt;async&lt;/code&gt; CE 📍&lt;/p&gt;
&lt;h2&gt;
  
  
  Monad
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Monad definition
&lt;/h3&gt;

&lt;p&gt;≃ Any generic type, noted &lt;code&gt;M&amp;lt;'T&amp;gt;&lt;/code&gt;, with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Construction function &lt;code&gt;return&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Signature : &lt;code&gt;(value: 'T) -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;≃ Wrap &lt;em&gt;(lift/elevate)&lt;/em&gt; a value&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chaining function &lt;code&gt;bind&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Noted &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; (&lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;=&lt;/code&gt;) as an infix operator&lt;/li&gt;
&lt;li&gt;Signature : &lt;code&gt;(f: 'T -&amp;gt; M&amp;lt;'U&amp;gt;) -&amp;gt; M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'U&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Take a &lt;strong&gt;monadic function&lt;/strong&gt; &lt;code&gt;f&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Call it with the eventual wrapped value(s)&lt;/li&gt;
&lt;li&gt;Get back a new monadic instance of this type&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Monad laws
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. &lt;strong&gt;Left Identity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;return&lt;/code&gt; then &lt;code&gt;bind&lt;/code&gt; are neutral.&lt;br&gt;
→ &lt;code&gt;return &amp;gt;&amp;gt; bind f&lt;/code&gt; ≡ &lt;code&gt;f&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. &lt;strong&gt;Right Identity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;bind return&lt;/code&gt; is neutral, equivalent to the &lt;code&gt;id&lt;/code&gt; function:&lt;br&gt;
→ &lt;code&gt;m |&amp;gt; bind return&lt;/code&gt; ≡ &lt;code&gt;m |&amp;gt; id&lt;/code&gt; ≡ &lt;code&gt;m&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;☝️ It's possible because &lt;code&gt;return&lt;/code&gt; has the signature of a monadic function.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. &lt;strong&gt;Associativity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;bind&lt;/code&gt; is associative.&lt;/p&gt;

&lt;p&gt;Given two monadic functions &lt;code&gt;f: 'a -&amp;gt; M&amp;lt;'b&amp;gt;&lt;/code&gt; and &lt;code&gt;g: 'b -&amp;gt; M&amp;lt;'c&amp;gt;&lt;/code&gt;&lt;br&gt;
→ &lt;code&gt;(m |&amp;gt; bind f) |&amp;gt; bind g&lt;/code&gt; ≡ &lt;code&gt;m |&amp;gt; bind (f &amp;gt;&amp;gt; bind g)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💡 &lt;code&gt;bind&lt;/code&gt; allows us to chain monadic functions, like the &lt;code&gt;|&amp;gt;&lt;/code&gt; for regular functions&lt;/p&gt;
&lt;h3&gt;
  
  
  Monad examples
&lt;/h3&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;Bind&lt;/th&gt;
&lt;th&gt;Return&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Option&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Option.bind&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Some&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Result&amp;lt;'T, _&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Result.bind&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ok&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;List&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;List.collect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;List.singleton&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Array&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Array.collect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Array.singleton&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Seq&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.collect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Seq.singleton&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Async&amp;lt;'T&amp;gt;&lt;/code&gt; too, but through the &lt;code&gt;async&lt;/code&gt; CE 📍&lt;/p&gt;
&lt;h3&gt;
  
  
  Monad &lt;em&gt;vs&lt;/em&gt; Functor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A monad is also a &lt;strong&gt;functor&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map&lt;/code&gt; can be expressed in terms of &lt;code&gt;bind&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt;:
&lt;code&gt;map f&lt;/code&gt; ≡ &lt;code&gt;bind (f &amp;gt;&amp;gt; return)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;☝️ &lt;strong&gt;Note:&lt;/strong&gt; Contrary to the monad with its &lt;code&gt;return&lt;/code&gt; operation, the functor concept does not need a "constructor" operation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Monad alternative definition
&lt;/h3&gt;

&lt;p&gt;A monad can be defined with the &lt;code&gt;flatten&lt;/code&gt; operation instead of the &lt;code&gt;bind&lt;/code&gt;&lt;br&gt;
→ Signature: &lt;code&gt;M&amp;lt;M&amp;lt;'T&amp;gt;&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, the &lt;code&gt;bind&lt;/code&gt; function can be expressed in terms of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;flatten&lt;/code&gt;:&lt;br&gt;
→ &lt;code&gt;bind&lt;/code&gt; ≡ &lt;code&gt;map &amp;gt;&amp;gt; flatten&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💡 This is why &lt;code&gt;bind&lt;/code&gt; is also called &lt;code&gt;flatMap&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Regular functions &lt;em&gt;vs&lt;/em&gt; monadic functions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th width="126"&gt;Function&lt;/th&gt;
&lt;th width="103"&gt;Op&lt;/th&gt;
&lt;th&gt;Signature&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pipeline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regular&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;▷&lt;/code&gt; &lt;em&gt;pipe&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(f: 'a -&amp;gt; 'b) -&amp;gt; (x: 'a) -&amp;gt; 'b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monadic&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; &lt;em&gt;bind&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(f: 'a -&amp;gt; M&amp;lt;'b&amp;gt;) -&amp;gt; (x: M&amp;lt;'a&amp;gt;) -&amp;gt; M&amp;lt;'b&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Composition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regular&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; &lt;em&gt;comp.&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(f: 'a -&amp;gt; 'b) -&amp;gt; (g: 'b -&amp;gt; 'c) -&amp;gt; ('a -&amp;gt; 'c)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monadic&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;gt;=&amp;gt;&lt;/code&gt; &lt;em&gt;fish&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(f: 'a -&amp;gt; M&amp;lt;'b&amp;gt;) -&amp;gt; (g: 'b -&amp;gt; M&amp;lt;'c&amp;gt;) -&amp;gt; ('a -&amp;gt; M&amp;lt;'c&amp;gt;)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Fish operator definition: &lt;code&gt;let (&amp;gt;=&amp;gt;) f g = fun x -&amp;gt; f x |&amp;gt; bind g&lt;/code&gt; ≡ &lt;code&gt;f &amp;gt;&amp;gt; (bind g)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Composition of monadic functions is called &lt;em&gt;Kleisli composition&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Monads &lt;em&gt;vs&lt;/em&gt; Effects
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Effect&lt;/strong&gt; &lt;em&gt;(a.k.a. "side effect")&lt;/em&gt;:&lt;br&gt;
→ change somewhere, inside the program &lt;em&gt;(state)&lt;/em&gt; or outside&lt;br&gt;
→ examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I/O&lt;/strong&gt; &lt;em&gt;(Input/Output):&lt;/em&gt; file read, console write, logging, network requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Management:&lt;/strong&gt; global variable update, database/table/row delete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exceptions/Errors:&lt;/strong&gt; program crash&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-determinism:&lt;/strong&gt; same input → ≠ value: random number, current time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency/Parallelism:&lt;/strong&gt; thread spawn, shared memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pure function causes no side effects → deterministic, predictable&lt;br&gt;
→ FP challenge: separate pure/impure code &lt;em&gt;(separation of concerns)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Monads purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulate and sequence computations that involve effects,&lt;/li&gt;
&lt;li&gt;Maintain purity of the surrounding functional code,&lt;/li&gt;
&lt;li&gt;Provide a controlled environment in which effects can happen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dealing with a computation that has an effect using monads means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Wrapping:&lt;/strong&gt; we don't get a value directly, we get a monadic value that represents the computation and its associated effect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequencing:&lt;/strong&gt; &lt;code&gt;bind&lt;/code&gt; (or &lt;code&gt;let!&lt;/code&gt; in a monadic CE) allows you to chain together effectful computations in a sequential order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Returning:&lt;/strong&gt; &lt;code&gt;return&lt;/code&gt; wraps a &lt;strong&gt;pure&lt;/strong&gt; value → computation w/o effects.
👉 A monadic sequence can mix pure and effectful computations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From the &lt;em&gt;caller&lt;/em&gt; perspective, a function returning a monadic value is &lt;strong&gt;pure.&lt;/strong&gt;&lt;br&gt;
→ Encapsulated effects only "happen" when monadic value is &lt;strong&gt;evaluated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Examples in F#:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Async&lt;/code&gt;: by calling &lt;code&gt;Async.RunSynchronously&lt;/code&gt;/&lt;code&gt;Start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Option&lt;/code&gt;/&lt;code&gt;Result&lt;/code&gt;: by pattern matching and handle all cases&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Seq&lt;/code&gt;: by iterating the delayed sequence of elements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Monads effectively bridge the gap between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mathematical elegance of pure functional programming&lt;/li&gt;
&lt;li&gt;practical necessity of interacting with an impure, stateful world&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Other common monads
&lt;/h3&gt;

&lt;p&gt;☝️ &lt;em&gt;Rarely used in F#, but common in Haskell&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reader&lt;/strong&gt;: to access a read-only environment (like configuration) throughout a computation without explicitly passing it around&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writer&lt;/strong&gt;: accumulates monoidal values (like logs) alongside a computation's primary result&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State&lt;/strong&gt;: manages a state that can be read and updated during a computation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IO&lt;/strong&gt;: handles I/O effects (disk, network calls...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;: to build series of instructions, separated from their execution (interpretation phase)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Applicative (Functor)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Applicative definition
&lt;/h3&gt;

&lt;p&gt;≃ Any generic type, noted &lt;code&gt;F&amp;lt;'T&amp;gt;&lt;/code&gt;, with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Construction function &lt;code&gt;pure&lt;/code&gt; (≡ monad's &lt;code&gt;return&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;Signature : &lt;code&gt;(value: 'T) -&amp;gt; F&amp;lt;'T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Application function &lt;code&gt;apply&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Noted &lt;code&gt;&amp;lt;*&amp;gt;&lt;/code&gt; (same &lt;code&gt;*&lt;/code&gt; as in tuple types)&lt;/li&gt;
&lt;li&gt;Signature : &lt;code&gt;(f: F&amp;lt;'T -&amp;gt; 'U&amp;gt;) -&amp;gt; F&amp;lt;'T&amp;gt; -&amp;gt; F&amp;lt;'U&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Similar to functor's &lt;code&gt;map&lt;/code&gt;, but where the mapping function &lt;code&gt;'T -&amp;gt; 'U&lt;/code&gt; is wrapped in the applicative object&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Applicative laws
&lt;/h3&gt;

&lt;p&gt;There are 4 laws:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Identity&lt;/em&gt; and &lt;em&gt;Homomorphism&lt;/em&gt; relatively easy to grasp&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Interchange&lt;/em&gt; and &lt;em&gt;Composition&lt;/em&gt; more tricky&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Law 1 - &lt;strong&gt;Identity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Same as the functor identity law applied to applicative:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Equation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Functor&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;map id F&lt;/code&gt; ≡ &lt;code&gt;F&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Applicative&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;apply (pure id) F&lt;/code&gt; ≡ &lt;code&gt;F&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Law 2 - &lt;strong&gt;Homomorphism&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;💡 &lt;em&gt;Homomorphism&lt;/em&gt; means a transformation that preserves the structure.&lt;/p&gt;

&lt;p&gt;→ &lt;code&gt;pure&lt;/code&gt; does not change the nature of values and functions so that we can apply the function to the value(s) either before or after being wrapped.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(pure f) &amp;lt;*&amp;gt; (pure x)&lt;/code&gt; ≡ &lt;code&gt;pure (f x)&lt;/code&gt; &lt;code&gt;apply (pure f) (pure x)&lt;/code&gt; ≡ &lt;code&gt;pure (f x)&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Law 3 - &lt;strong&gt;Interchange&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We can provide the wrapped function &lt;code&gt;Ff&lt;/code&gt; first or the value &lt;code&gt;x&lt;/code&gt;, wrapped directly or captured in &lt;code&gt;(|&amp;gt;) x&lt;/code&gt; &lt;em&gt;(partial application of the &lt;code&gt;|&amp;gt;&lt;/code&gt; operator used as function)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Ff &amp;lt;*&amp;gt; (pure x)&lt;/code&gt; ≡ &lt;code&gt;pure ((|&amp;gt;) x) &amp;lt;*&amp;gt; Ff&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💡 When &lt;code&gt;Ff&lt;/code&gt; = &lt;code&gt;pure f&lt;/code&gt;, we can verify this law with the homomorphism law:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apply Ff (pure x)       | apply (pure ((|&amp;gt;) x)) Ff
apply (pure f) (pure x) | apply (pure ((|&amp;gt;) x)) (pure f)
pure (f x)              | pure (((|&amp;gt;) x) f)
                        | pure (x |&amp;gt; f)
                        | pure (f x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Law 4 - &lt;strong&gt;Composition&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Cornerstone law: ensures that function composition works as expected within the applicative context.&lt;/li&gt;
&lt;li&gt;Hardest law, involving to wrap the &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; operator (right-to-left compose)!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Ff &amp;lt;*&amp;gt; (Fg &amp;lt;*&amp;gt; Fx)&lt;/code&gt; ≡ &lt;code&gt;(pure (&amp;lt;&amp;lt;) &amp;lt;*&amp;gt; Ff &amp;lt;*&amp;gt; Fg) &amp;lt;*&amp;gt; Fx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💡 Same verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(pure f) &amp;lt;*&amp;gt; ((pure g) &amp;lt;*&amp;gt; (pure x))    | (pure (&amp;lt;&amp;lt;) &amp;lt;*&amp;gt; (pure f) &amp;lt;*&amp;gt; (pure g)) &amp;lt;*&amp;gt; (pure x)
(pure f) &amp;lt;*&amp;gt; (pure g x)                 | (pure ((&amp;lt;&amp;lt;) f) &amp;lt;*&amp;gt; (pure g)) &amp;lt;*&amp;gt; (pure x)
pure (f (g x))                          | (pure ((&amp;lt;&amp;lt;) f g)) &amp;lt;*&amp;gt; (pure x)
pure ((f &amp;lt;&amp;lt; g) x)                       | (pure (f &amp;lt;&amp;lt; g)) &amp;lt;*&amp;gt; (pure x)
                                        | pure ((f &amp;lt;&amp;lt; g) x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Applicative &lt;em&gt;vs&lt;/em&gt; Functor
&lt;/h3&gt;

&lt;p&gt;Every applicative is a functor.&lt;br&gt;
→ We can define &lt;code&gt;map&lt;/code&gt; with &lt;code&gt;pure&lt;/code&gt; and &lt;code&gt;apply&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;map f x&lt;/code&gt; ≡ &lt;code&gt;apply (pure f) x&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💡 It was implied by the 2 identity laws.&lt;/p&gt;
&lt;h3&gt;
  
  
  Applicative &lt;em&gt;vs&lt;/em&gt; Monad
&lt;/h3&gt;

&lt;p&gt;Every monad is also an applicative&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pure&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt; are just synonyms&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apply&lt;/code&gt; can be defined using &lt;code&gt;bind&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;given &lt;code&gt;mx&lt;/code&gt; a wrapped value &lt;code&gt;M&amp;lt;'a&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;mf&lt;/code&gt; a wrapped function &lt;code&gt;M&amp;lt;'a -&amp;gt; 'b&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apply mf mx&lt;/code&gt; ≡ &lt;code&gt;mf |&amp;gt; bind (fun f -&amp;gt; mx |&amp;gt; bind (fun x -&amp;gt; return (f x)))&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;apply&lt;/code&gt; &lt;em&gt;vs&lt;/em&gt; &lt;code&gt;bind&lt;/code&gt; 💡&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where &lt;code&gt;apply&lt;/code&gt; unwraps both &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt;, 2 nested &lt;code&gt;bind&lt;/code&gt;s are required.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bind&lt;/code&gt; extra power comes from its ability to let its first parameter — the function &lt;code&gt;'a -&amp;gt; M&amp;lt;'b&amp;gt;&lt;/code&gt; — create a whole new computational path.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Applicative: multi-param curried function
&lt;/h3&gt;

&lt;p&gt;Applicative helps to apply a function to its arguments (e.g. &lt;code&gt;f: 'x -&amp;gt; 'y -&amp;gt; 'res&lt;/code&gt;) when they are each wrapped (e.g. in an &lt;code&gt;Option&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Let's try by hand:&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;call&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;optionalX&lt;/span&gt; &lt;span class="n"&gt;optionalY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optionalY&lt;/span&gt;&lt;span class="p"&gt;)&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;x&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;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;f&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&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="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 We can recognize the &lt;code&gt;Option.map2&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;🤔 Is there a way to handle any number of parameters?&lt;/p&gt;

&lt;p&gt;The solution is to use &lt;code&gt;apply&lt;/code&gt; N times, for each of the N arguments, first wrapping the function using &lt;code&gt;pure&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="c1"&gt;// apply and pure for the Option type&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;optionalF&lt;/span&gt; &lt;span class="n"&gt;optionalX&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optionalX&lt;/span&gt;&lt;span class="p"&gt;)&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;f&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;x&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;f&lt;/span&gt; &lt;span class="n"&gt;x&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="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;pure&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;Some&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="c1"&gt;// ---&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;optionalX&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;1&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;optionalY&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;2&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;optionalZ&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;3&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;pure&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;apply&lt;/span&gt; &lt;span class="n"&gt;optionalX&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;optionalY&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;optionalZ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternative syntax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the operators for map &lt;code&gt;&amp;lt;!&amp;gt;&lt;/code&gt; and apply &lt;code&gt;&amp;lt;*&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Given we can replace the 1st combination of &lt;code&gt;pure&lt;/code&gt; and &lt;code&gt;apply&lt;/code&gt; with &lt;code&gt;map&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;!&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalX&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalY&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalZ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still, it's not ideal!&lt;/p&gt;

&lt;h3&gt;
  
  
  Applicative styles
&lt;/h3&gt;

&lt;p&gt;The previous syntax is called &lt;strong&gt;❝Style A❞&lt;/strong&gt; and is not recommended in modern F# by Don Syme - see his &lt;a href="https://github.com/dsyme/fsharp-presentations/blob/master/design-notes/rethinking-applicatives.md" rel="noopener noreferrer"&gt;Nov. 2020 design note&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we use the &lt;code&gt;mapN&lt;/code&gt; functions, it's called &lt;strong&gt;❝Style B❞&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;❝Style C❞&lt;/strong&gt; relies on F# 5 &lt;code&gt;let! ... and! ...&lt;/code&gt; in a CE like &lt;code&gt;option&lt;/code&gt; from &lt;code&gt;FsToolkit&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;res''&lt;/span&gt; &lt;span class="p"&gt;=&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;let&lt;/span&gt;&lt;span class="o"&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;optionalX&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optionalY&lt;/span&gt;
        &lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optionalZ&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Avoid style A, prefer style C when a CE is available, otherwise style B.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applicative &lt;em&gt;vs&lt;/em&gt; Monadic behaviour
&lt;/h3&gt;

&lt;p&gt;The monadic behaviour is &lt;strong&gt;sequential&lt;/strong&gt;:&lt;br&gt;
→ The computation #n+1 is done only after the computation #n.&lt;/p&gt;

&lt;p&gt;The applicatives behave in &lt;strong&gt;parallel&lt;/strong&gt;:&lt;br&gt;
→ All the computations for the arguments are done before applying them to the wrapped function.&lt;/p&gt;

&lt;p&gt;👉 Even if monads can do more things, applicatives can be more performant on what they can do.&lt;/p&gt;
&lt;h3&gt;
  
  
  Applicative parallel behaviour
&lt;/h3&gt;

&lt;p&gt;The corollary is about the &lt;code&gt;Result&lt;/code&gt; type and its &lt;code&gt;bind&lt;/code&gt; function:&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;bind&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;_&amp;gt;)&lt;/span&gt; &lt;span class="n"&gt;result&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;result&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;Ok&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;f&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;Error&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="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ As soon as the current &lt;code&gt;result&lt;/code&gt; is an &lt;code&gt;Error&lt;/code&gt; case, &lt;code&gt;f&lt;/code&gt; is ignored.&lt;br&gt;
→ On the 1st error, we "unplug".&lt;/p&gt;

&lt;p&gt;Given the &lt;code&gt;Result&amp;lt;'ok, 'error list&amp;gt;&lt;/code&gt; type, &lt;code&gt;apply&lt;/code&gt; can accumulate errors:&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;apply&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;rf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&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;Ok&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;Ok&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="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;fErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;fErrors&lt;/span&gt;                      &lt;span class="c1"&gt;// (4)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="o"&gt;_,&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;xErrors&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;xErrors&lt;/span&gt;                      &lt;span class="c1"&gt;// (5)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;fErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;xErrors&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xErrors&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;fErrors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// (6)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Errors are either accumulated &lt;em&gt;(line 6)&lt;/em&gt; or propagated &lt;em&gt;(lines 4, 5)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;At lines 4 and 6, &lt;code&gt;rf&lt;/code&gt; is no longer a wrapped function but an &lt;code&gt;Error&lt;/code&gt;. It happens after a first &lt;code&gt;apply&lt;/code&gt; when there is an &lt;code&gt;Error&lt;/code&gt; instead of a wrapped value &lt;em&gt;(lines 5, 6)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 Handy for validating inputs and reporting all errors to the user.&lt;br&gt;
🔗 &lt;a href="https://www.compositional-it.com/news-blog/validation-with-f-5-and-fstoolkit/" rel="noopener noreferrer"&gt;Validation with F# 5 and FsToolkit&lt;/a&gt;, Compositional IT&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Functional patterns key points
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th width="142"&gt;Pattern&lt;/th&gt;
&lt;th&gt;Key words&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monoid&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;+&lt;/code&gt; (combine), composite design pattern ++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Functor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;map&lt;/code&gt;, preserve structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monad&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;bind&lt;/code&gt;, functor, flatten, sequential composition, effects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Applicative&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;apply&lt;/code&gt;, functor, multi-params function, parallel composition&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Functional patterns in F# language
&lt;/h3&gt;

&lt;p&gt;In F#, these functional patterns are applied under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monoids with &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt; and functions&lt;/li&gt;
&lt;li&gt;Monads with &lt;code&gt;Async&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;All patterns when using computation expressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;☝️ After the beginner level, it's best to know the principles of these patterns, in case we need to write computation expressions.&lt;/p&gt;

&lt;h4&gt;
  
  
  🤔 Make these patterns more explicit in F# codebases?
&lt;/h4&gt;

&lt;p&gt;Meaning: what about F# codebases full of &lt;code&gt;monad&lt;/code&gt;, &lt;code&gt;Reader&lt;/code&gt;, &lt;code&gt;State&lt;/code&gt;...?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generally &lt;strong&gt;not recommended&lt;/strong&gt;, at least by Don Syme

&lt;ul&gt;
&lt;li&gt;Indeed, the F# language is not designed that way.&lt;/li&gt;
&lt;li&gt;Although, libraries such as &lt;em&gt;FSharpPlus&lt;/em&gt; offer such extensions to F#.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;To be evaluated for each team: idiomatic &lt;em&gt;vs&lt;/em&gt; consistency ⚖️
→ Examples:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idiomatic F#&lt;/strong&gt; recommended in .NET teams using both C♯ and F# code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Functional F#&lt;/strong&gt; can be considered in FP teams using several functional languages: F#, Haskell, OCaml...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional resources 🔗
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://fsharpforfunandprofit.com/posts/monoids-without-tears/#series-toc" rel="noopener noreferrer"&gt;"Understanding monoids" series&lt;/a&gt; —F# for Fun and Profit&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kutt.it/ebfGNA" rel="noopener noreferrer"&gt;"Map and Bind and Apply, Oh my!" series&lt;/a&gt; —F# for Fun and Profit&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.ploeh.dk/2022/03/28/monads/" rel="noopener noreferrer"&gt;Monads series&lt;/a&gt; —Mark Seemann&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thinkbeforecoding.com/post/2020/10/03/applicatives-irl" rel="noopener noreferrer"&gt;Applicatives IRL&lt;/a&gt; —Jeremie Chassaing&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>functional</category>
    </item>
    <item>
      <title>F# Computation Expressions 🧑‍🏫</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Fri, 22 Aug 2025 13:09:00 +0000</pubDate>
      <link>https://dev.to/rdeneau/f-computation-expressions-4ge6</link>
      <guid>https://dev.to/rdeneau/f-computation-expressions-4ge6</guid>
      <description>&lt;p&gt;Computation expressions—abbreviated as CE—are among the most powerful features of F#: they are not just syntactic sugar, but also an entry point for extending the F# language locally. They have been carefully designed to provide a great deal of flexibility, making them a unique and distinctive feature compared to what other programming languages offer.&lt;/p&gt;

&lt;p&gt;This power and flexibility come at a price: the available literature on the topic is scarce. Scott Wlaschin has made a great effort to popularize the topic on F# for Fun and Profit, especially with the &lt;a href="https://fsharpforfunandprofit.com/series/computation-expressions/" rel="noopener noreferrer"&gt;"Computation Expressions" series&lt;/a&gt;. Everything is accurate and still relevant; it just lacks coverage of the latest F# features such as the &lt;code&gt;and!&lt;/code&gt; keyword. While the articles are designed to be educational, this material is not optimal as a reference when writing your own computation expressions.&lt;/p&gt;

&lt;p&gt;As for the documentation on &lt;a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions" rel="noopener noreferrer"&gt;Microsoft Learn&lt;/a&gt;, it is concise and complementary to Scott Wlaschin's articles. This conciseness results in a lack of precision that makes it unsuitable for getting started with writing CEs.&lt;/p&gt;

&lt;p&gt;This series of articles offers an alternative approach: it aims to present the concepts underlying CEs—which we call functional patterns—to F# programmers, in order to categorize the types of CEs that you might need to design. The base material comes from my F# training, available in this &lt;a href="https://rdeneau.gitbook.io/fsharp-training/" rel="noopener noreferrer"&gt;GitBook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;
Introduction

&lt;ul&gt;
&lt;li&gt;Syntax&lt;/li&gt;
&lt;li&gt;Functional patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Builder

&lt;ul&gt;
&lt;li&gt;Builder example: &lt;code&gt;logger {}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Bind&lt;/code&gt; &lt;em&gt;vs&lt;/em&gt; &lt;code&gt;let!&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;CE desugaring: tips 💡&lt;/li&gt;
&lt;li&gt;Constructor parameters&lt;/li&gt;
&lt;li&gt;Builder example: &lt;code&gt;option {}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The page on &lt;a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions" rel="noopener noreferrer"&gt;Microsoft Learn&lt;/a&gt; is the ideal entry point into the subject:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Computation expressions in F# provide a convenient &lt;strong&gt;syntax&lt;/strong&gt; for writing computations that can be sequenced and combined using control flow constructs and bindings.&lt;/li&gt;
&lt;li&gt;Depending on the kind of computation expression, they can be thought of as a way to express monads, monoids, monad transformers, and applicatives.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Syntax
&lt;/h3&gt;

&lt;p&gt;With regard to the first point, as F# provides &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;task&lt;/code&gt;, and &lt;code&gt;seq&lt;/code&gt;  computation expressions directly in &lt;code&gt;FSharp.Core&lt;/code&gt;, you can quickly be led to use them and find that, indeed, CEs are relatively easy to use—I say relatively because they are still harder to master than C#'s &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; pattern.&lt;/p&gt;

&lt;p&gt;The syntax of a CE can be summarized in a block of code such as &lt;code&gt;myCE { body }&lt;/code&gt; where &lt;code&gt;body&lt;/code&gt; looks like &lt;strong&gt;imperative&lt;/strong&gt; F# code with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regular keywords: &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;do&lt;/code&gt;, &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;then&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt;, &lt;code&gt;match&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;Dedicated keywords: &lt;code&gt;yield&lt;/code&gt;, &lt;code&gt;return&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;"Banged" keywords: &lt;code&gt;let!&lt;/code&gt;, &lt;code&gt;do!&lt;/code&gt;, &lt;code&gt;match!&lt;/code&gt;, &lt;code&gt;yield!&lt;/code&gt;, &lt;code&gt;return!&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These keywords hide a ❝ &lt;strong&gt;machinery&lt;/strong&gt; ❞ to perform background &lt;strong&gt;specific&lt;/strong&gt; effects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asynchronous computations like with &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;task&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;State management: e.g. a sequence with &lt;code&gt;seq&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Absence of a value with &lt;code&gt;option&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Error handling with &lt;code&gt;result&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Functional patterns
&lt;/h3&gt;

&lt;p&gt;"Monads, monoids, monad transformers, and applicatives" are the functional patterns mentioned just above. These patterns are only mentioned in passing: they are not explained and are not used to organize the documentation. On the F# for Fun and Profit website, Scott deliberately avoids explicitly mentioning these functional patterns: with the exception of the monoid with the &lt;a href="https://fsharpforfunandprofit.com/series/understanding-monoids/" rel="noopener noreferrer"&gt;"Understanding monoids" series&lt;/a&gt;, the other patterns are not explained from the front, but from the point of view of their operations: &lt;code&gt;map&lt;/code&gt; for functors, &lt;code&gt;bind&lt;/code&gt; for monads, ... - see &lt;a href="https://fsharpforfunandprofit.com/series/map-and-bind-and-apply-oh-my/" rel="noopener noreferrer"&gt;"Map and Bind and Apply, Oh my!" series&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The available literature about these patterns is extensive, but can be arduous to work through, especially for .NET developers with no experience of other strongly typed functional languages such as Haskell and Scala. We'll look at each of these patterns in detail, either because they're already built into the F# language, sometimes without us even realizing it, or to help us write a kind of CE related to one of these patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Builder
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;computation expression&lt;/em&gt; relies on an object called &lt;em&gt;Builder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; This is not exactly the &lt;em&gt;Builder&lt;/em&gt; object-oriented design pattern.&lt;/p&gt;

&lt;p&gt;For each supported &lt;strong&gt;keyword&lt;/strong&gt; (&lt;code&gt;let!&lt;/code&gt;, &lt;code&gt;return&lt;/code&gt;...), the &lt;em&gt;Builder&lt;/em&gt; implements one or more related &lt;strong&gt;methods&lt;/strong&gt;. The compiler provides &lt;strong&gt;flexibility&lt;/strong&gt; in the builder &lt;strong&gt;method signatures&lt;/strong&gt;, as long as the methods can be &lt;strong&gt;chained together&lt;/strong&gt; properly when the compiler evaluates the CE's body on the &lt;strong&gt;caller side.&lt;/strong&gt; This versatility is powerful, but can lead to difficulties in designing and testing a CE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Builder example: &lt;code&gt;logger {}&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Need: log the intermediate values of a calculation&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;// First version&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;"{value}"&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;loggedCalc&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;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;  &lt;span class="c1"&gt;// ❶&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;  &lt;span class="c1"&gt;// ❶&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;  &lt;span class="c1"&gt;// ❶&lt;/span&gt;
    &lt;span class="n"&gt;z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ &lt;strong&gt;Issues&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verbose: the &lt;code&gt;log x&lt;/code&gt; interfere with reading&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Error prone&lt;/em&gt;: forget a &lt;code&gt;log&lt;/code&gt;, log wrong value...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 &lt;strong&gt;Solutions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make logs implicit in a CE by implementing a custom &lt;code&gt;let!&lt;/code&gt;/&lt;code&gt;Bind()&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;type&lt;/span&gt; &lt;span class="nc"&gt;LoggerBuilder&lt;/span&gt;&lt;span class="bp"&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;log&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;"{value}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;value&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;Bind&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;f&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;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&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;member&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Return&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;//---&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;loggedCalc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;     &lt;span class="c1"&gt;// 👈 Implicitly perform `log x`&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;     &lt;span class="c1"&gt;// 👈                    `log y`&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;  &lt;span class="c1"&gt;// 👈                    `log z`&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three consecutive &lt;code&gt;let!&lt;/code&gt; statements are desugared into three &lt;strong&gt;nested&lt;/strong&gt; calls to &lt;code&gt;Bind&lt;/code&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1st argument: the right side of the &lt;code&gt;let!&lt;/code&gt; (e.g. &lt;code&gt;42&lt;/code&gt; with &lt;code&gt;let! x = 42&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;2nd argument: a lambda taking the variable defined at the left side of the &lt;code&gt;let!&lt;/code&gt; (e.g. &lt;code&gt;x&lt;/code&gt;) and returning the whole expression below the &lt;code&gt;let!&lt;/code&gt; until the &lt;code&gt;}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// let! x = 42&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&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="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="c1"&gt;// let! y = 43&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;43&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;y&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;// let! z = x + y&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&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;z&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;// return z&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Return&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;Bind&lt;/code&gt; &lt;em&gt;vs&lt;/em&gt; &lt;code&gt;let!&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;logger { let! var = expr in cexpr }&lt;/code&gt; is desugared as:&lt;br&gt;
&lt;code&gt;logger.Bind(expr, fun var -&amp;gt; cexpr)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Key points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;var&lt;/code&gt; and &lt;code&gt;expr&lt;/code&gt; appear in reverse order&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;var&lt;/code&gt; is used in the rest of the computation &lt;code&gt;cexpr&lt;/code&gt;
→ highlighted using the &lt;code&gt;in&lt;/code&gt; keyword of the verbose syntax&lt;/li&gt;
&lt;li&gt;the lambda &lt;code&gt;fun var -&amp;gt; cexpr&lt;/code&gt; is a &lt;strong&gt;continuation&lt;/strong&gt; function&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  CE desugaring: tips 💡
&lt;/h3&gt;

&lt;p&gt;I found a simple way to desugar computation expressions:&lt;br&gt;
→ Write a failing unit test and use &lt;a href="https://github.com/SwensenSoftware/unquote" rel="noopener noreferrer"&gt;Unquote&lt;/a&gt; - 🔗 &lt;a href="https://github.com/rdeneau/formation-fsharp/blob/main/src/FSharpTraining/04-Monad/LoggerTests.fs#L42" rel="noopener noreferrer"&gt;Example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9xwcjmj9nahpr5rlkqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9xwcjmj9nahpr5rlkqk.png" alt="CE desugaring with Unquote"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Constructor parameters
&lt;/h3&gt;

&lt;p&gt;The builder can be constructed with additional parameters.&lt;br&gt;
→ The CE syntax allows us to pass these arguments when using the CE:&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;LoggerBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;"{prefix}{value}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;value&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;Bind&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;f&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;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&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;member&lt;/span&gt; &lt;span class="o"&gt;_.&lt;/span&gt;&lt;span class="nc"&gt;Return&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//---&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;loggedCalc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="s2"&gt;"[Debug] "&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;     &lt;span class="c1"&gt;// 👈 Output "[Debug] 42"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;     &lt;span class="c1"&gt;// 👈 Output "[Debug] 43"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;  &lt;span class="c1"&gt;// 👈 Output "[Debug] 85"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Builder example: &lt;code&gt;option {}&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Need: successively try to find values in maps using identifiers&lt;br&gt;
→ Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find &lt;code&gt;policyCode&lt;/code&gt; by &lt;code&gt;roomRateId&lt;/code&gt; in &lt;code&gt;policyCodesByRoomRate&lt;/code&gt; map&lt;/li&gt;
&lt;li&gt;Find &lt;code&gt;policyType&lt;/code&gt; by &lt;code&gt;policyCode&lt;/code&gt; in &lt;code&gt;policyTypesByCode&lt;/code&gt; map&lt;/li&gt;
&lt;li&gt;Build the "result" from both &lt;code&gt;policyCode&lt;/code&gt; and &lt;code&gt;policyType&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Implementation #1: based on match expressions
&lt;/h4&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;policyCodesByRoomRate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomRateId&lt;/span&gt;&lt;span class="p"&gt;)&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;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;Some&lt;/span&gt; &lt;span class="n"&gt;policyCode&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;policyTypesByCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policyCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;  &lt;span class="c1"&gt;// ⚠️ Nesting&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="nc"&gt;None&lt;/span&gt;                                    &lt;span class="c1"&gt;// ⚠️ Duplicates line 2&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;policyType&lt;/span&gt; &lt;span class="p"&gt;-&amp;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;buildResult&lt;/span&gt; &lt;span class="n"&gt;policyCode&lt;/span&gt; &lt;span class="n"&gt;policyType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implementation #2: based on &lt;code&gt;Option&lt;/code&gt; module helpers
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="n"&gt;policyCodesByRoomRate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomRateId&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;Option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&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;policyCode&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;policyTypesByCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policyCode&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;Option&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;policyType&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buildResult&lt;/span&gt; &lt;span class="n"&gt;policyCode&lt;/span&gt; &lt;span class="n"&gt;policyType&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;👉 Issues ⚠️:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nesting too&lt;/li&gt;
&lt;li&gt;Even more difficult to read because of parentheses&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation #3: based on the &lt;code&gt;option {}&lt;/code&gt; CE
&lt;/h4&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;OptionBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&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;Bind&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;f&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;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt; &lt;span class="n"&gt;f&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;Return&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="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OptionBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&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;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;policyCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;policyCodesByRoomRate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomRateId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;policyType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;policyTypesByCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policyCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;buildResult&lt;/span&gt; &lt;span class="n"&gt;policyCode&lt;/span&gt; &lt;span class="n"&gt;policyType&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Both terse and readable ✅🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After this introduction to computation expressions and their builders, illustrated with the &lt;code&gt;logger {}&lt;/code&gt; and &lt;code&gt;option {}&lt;/code&gt; CEs, let's study functional patterns. We'll then look at how to write monoidal CEs, monadic CEs, and applicative CEs.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>functional</category>
    </item>
    <item>
      <title>Welcome, Commitji!</title>
      <dc:creator>Romain Deneau</dc:creator>
      <pubDate>Wed, 16 Jul 2025 07:35:02 +0000</pubDate>
      <link>https://dev.to/rdeneau/welcome-commitji-2j7m</link>
      <guid>https://dev.to/rdeneau/welcome-commitji-2j7m</guid>
      <description>&lt;p&gt;&lt;em&gt;Commitji&lt;/em&gt; is a dotnet tool available on &lt;a href="https://www.nuget.org/packages/Commitji.Cli" rel="noopener noreferrer"&gt;NuGet&lt;/a&gt;. I've created this CLI tool to complement our usual commit tool to help us write conventional commit messages that both include an emoji from Gitmoji and are compatible with semantic release.&lt;/p&gt;

&lt;p&gt;
  Table of contents
  &lt;ul&gt;
&lt;li&gt;
Issues at stake

&lt;ul&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;Conventions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Commitji message template

&lt;ul&gt;
&lt;li&gt;Prefix&lt;/li&gt;
&lt;li&gt;Emoji&lt;/li&gt;
&lt;li&gt;Breaking change&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Installation

&lt;ul&gt;
&lt;li&gt;Run in a terminal&lt;/li&gt;
&lt;li&gt;Run in a dedicated windows&lt;/li&gt;
&lt;li&gt;Run in GitExtensions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Usage

&lt;ul&gt;
&lt;li&gt;Steps&lt;/li&gt;
&lt;li&gt;Behaviors&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Edit&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues at stake
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tools
&lt;/h3&gt;

&lt;p&gt;You may have a preferred tool to create commits. For instance, on Windows, I use &lt;a href="https://gitextensions.github.io" rel="noopener noreferrer"&gt;GitExtensions&lt;/a&gt; 🤩 - powerful user-interface for &lt;code&gt;git&lt;/code&gt; and very handy, as long as you don't mind using the mouse.&lt;/p&gt;

&lt;p&gt;👉 Commitji is not a replacement for such a tool, it is complementary to it, to help you write commit messages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You start in your usual tool to refine the changes you want to commit,&lt;/li&gt;
&lt;li&gt;You run &lt;code&gt;commitji&lt;/code&gt; in a (separate) terminal to get the commit message template,&lt;/li&gt;
&lt;li&gt;You get back to your tool to paste the template, complete it to get a full commit message, and commit the changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conventions
&lt;/h3&gt;

&lt;p&gt;Following a convention in your commit messages helps to read the commit history. But there are several conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.conventionalcommits.org" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt; uses prefixes like &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gitmoji.dev/" rel="noopener noreferrer"&gt;Gitmoji&lt;/a&gt; uses emojis to indicate the type of change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are interesting, but they are not compatible with each other. Moreover, only a subset of the conventional commits template is supported by &lt;a href="https://semantic-release.gitbook.io/semantic-release" rel="noopener noreferrer"&gt;semantic release&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commitji message template
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Commitji&lt;/em&gt; allows you to get the best of the three worlds, by following conventional commits compatible with semantic release, while using emojis to clarify the type of change, to end up with this template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;prefix&amp;gt;: &amp;lt;emoji&amp;gt; #description
&amp;lt;BLANK LINE&amp;gt;
[BREAKING CHANGE: #explanation]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prefix
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;prefix&amp;gt;&lt;/code&gt;, called &lt;code&gt;type&lt;/code&gt; in conventional commits, indicates the type of change.&lt;/p&gt;

&lt;p&gt;There are 9 prefixes available, almost all directly supported by semantic release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The more important: &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The other prefixes: &lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;docs&lt;/code&gt;, &lt;code&gt;perf&lt;/code&gt;, &lt;code&gt;revert&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that there are no &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;ci&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build&lt;/code&gt; and &lt;code&gt;ci&lt;/code&gt; can be included

&lt;ul&gt;
&lt;li&gt;in the &lt;code&gt;&amp;lt;scope&amp;gt;&lt;/code&gt; of the &lt;code&gt;chore&lt;/code&gt; prefix, e.g. &lt;code&gt;chore(build): ⬆️ bump dependencies&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;in the &lt;code&gt;#description&lt;/code&gt;, e.g. &lt;code&gt;chore: 🐛 fix CI build&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;style&lt;/code&gt; is confusing and not needed:

&lt;ul&gt;
&lt;li&gt;When it means a change in the code style, we can use &lt;code&gt;refactor&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;When it's used for a change in the UI style, it's probably rather a &lt;code&gt;feat&lt;/code&gt; or a &lt;code&gt;fix&lt;/code&gt; that you can complement with an UI emoji:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dizzy……… :&lt;/code&gt; 💫 Add or update animations and transitions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iphone…… :&lt;/code&gt; 📱 Work on responsive design.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lipstick :&lt;/code&gt; 💄 Change the UI visually but not it's behaviour.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Emoji
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;emoji&amp;gt;&lt;/code&gt; complements the &lt;code&gt;&amp;lt;prefix&amp;gt;&lt;/code&gt;. It is placed in front of the description to clarify the type of change.&lt;/p&gt;

&lt;p&gt;There are 75 emojis available, most of them from Gitmoji. It is quite a lot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you know well some emojis, you may start by selecting the emoji, and then the prefix amongst those compatibles.&lt;/li&gt;
&lt;li&gt;Otherwise, it is usually more convenient to start with the prefix, and then select the emoji amongst the shorter list of emojis compatible with the selected prefix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Commitji related features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Start step:&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;By default, you start by selecting the prefix.&lt;/li&gt;
&lt;li&gt;It's possible to switch to start by selecting the emoji.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;Quick search:&lt;/em&gt; the selection is made with the keyboard, by starting to type the emoji/prefix code - e.g. type &lt;code&gt;spa&lt;/code&gt; to select &lt;code&gt;sparkles ✨&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Gitmoji indicates the emoji codes used on GitHub. But, they may differ on other platforms you are more accustomed to, like the OS of your mobile phone or the emoji picker on Windows 11 (&lt;code&gt;[Windows]+[.]&lt;/code&gt;).&lt;br&gt;
→ For instance, the &lt;a href="https://emojipedia.org/check-mark-button#technical" rel="noopener noreferrer"&gt;&lt;em&gt;Check Mark Button&lt;/em&gt; ✅&lt;/a&gt; has the code &lt;code&gt;:white_check_mark:&lt;/code&gt; on GitHub, but it is &lt;code&gt;check mark button&lt;/code&gt; on Windows 11, and is also known as &lt;em&gt;Green Tick&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;👉 Commitji related features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The emoji is inserted in the commit message as a Unicode character, not as a code.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Full-text search&lt;/em&gt; : what you type is searched inside the code and the description - e.g. type &lt;code&gt;depe&lt;/code&gt; to select a change related to a dependency:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arrow_down……………… :&lt;/code&gt; ⬇️ Downgrade dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;arrow_up…………………… :&lt;/code&gt; ⬆️ Upgrade dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;heavy_minus_sign :&lt;/code&gt; ➖ Remove a dependency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;heavy_plus_sign… :&lt;/code&gt; ➕ Add a dependency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pushpin……………………… :&lt;/code&gt; 📌 Pin dependencies to specific versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[v1.2] support of more codes, including aliases specified in &lt;a href="https://emojipedia.org/" rel="noopener noreferrer"&gt;Emojipedia&lt;/a&gt;
e.g. Type &lt;code&gt;tick&lt;/code&gt; to select either &lt;code&gt;lipstick 💄&lt;/code&gt; or &lt;code&gt;check_mark ✅&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[v1.3] auto-expanding search: if what you have typed does not match the current search mode or the current start step, before indicating that no match is found, the tool tries to auto-expand the search mode and/or the current start step to match the input.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Breaking change
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;BREAKING CHANGE&lt;/code&gt; is an optional section to indicate a breaking change.&lt;/p&gt;

&lt;p&gt;👉 Commitji ensures the compatibility with semantic release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's placed on a separate line&lt;/li&gt;
&lt;li&gt;there are no &lt;code&gt;!&lt;/code&gt; at the end of &lt;code&gt;type&lt;/code&gt; (e.g. &lt;code&gt;feat!&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;💡 the emoji &lt;code&gt;boom&lt;/code&gt; 💥 is used instead to get the same effect&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;☝️ Indicate a breaking change wisely: it's not just about a technical change that may break the code; it should be related to an improvement in your product that is worth the migration cost for your users.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://aaronstannard.com/oss-semver/" rel="noopener noreferrer"&gt;Practical vs. Strict Semantic Versioning&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Commitji is available as a .NET global tool. You can install it using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Commitji.Cli&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run in a terminal
&lt;/h3&gt;

&lt;p&gt;You can run Commitji with the command &lt;code&gt;commitji&lt;/code&gt; in a terminal. But notice that it will clear the console!&lt;/p&gt;

&lt;h3&gt;
  
  
  Run in a dedicated windows
&lt;/h3&gt;

&lt;p&gt;There are several ways to run Commitji in a dedicated windows.&lt;/p&gt;

&lt;p&gt;For instance on Windows you can use the command &lt;code&gt;cmd.exe /c "title Commitji &amp;amp;&amp;amp; commitji"&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/c&lt;/code&gt; is to close the windows at the end. Use &lt;code&gt;/k&lt;/code&gt; if you want to keep it open.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title Commitji&lt;/code&gt; is just to ensure that the windows will have a nice title.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Run in GitExtensions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gitextensions.github.io" rel="noopener noreferrer"&gt;GitExtensions&lt;/a&gt; allows to define a custom script and to attach a hotkey to run it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;em&gt;Settings &amp;gt; Scripts&lt;/em&gt;, add a script with the following properties. Then, press &lt;code&gt;[OK]&lt;/code&gt; (and not &lt;code&gt;[Apply]&lt;/code&gt;) to save the settings.

&lt;ul&gt;
&lt;li&gt;Name: Commitji&lt;/li&gt;
&lt;li&gt;Command: &lt;code&gt;$host.UI.RawUI.WindowTitle = 'Commitji'; commitji&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Is PowerShell script: True&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;Settings &amp;gt; Hotkeys&lt;/em&gt;, attach a keyboard shortcut to run the previous script - e.g. &lt;code&gt;[Ctrl]+[.]&lt;/code&gt; &lt;em&gt;(&lt;code&gt;[OemPeriod]&lt;/code&gt;),&lt;/em&gt; in reference to &lt;code&gt;[Win]+[.]&lt;/code&gt; to open the emoji picker in Windows 11.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, when you want to commit your changes, you can press:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[Ctrl]+[Space]&lt;/code&gt; to open the &lt;em&gt;Commit&lt;/em&gt; popup&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[Ctrl]+[.]&lt;/code&gt; to open &lt;em&gt;Commitji&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;complete all steps until the commit message template copied in the clipboard&lt;/li&gt;
&lt;li&gt;paste it in the &lt;em&gt;Commit message&lt;/em&gt; text area&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;p&gt;The tool display a series of questions, mainly to allow you to choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a prefix (&lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;...) and an emoji amongst a short list of relevant emojis (e.g. &lt;code&gt;sparkles&lt;/code&gt; ✨ for &lt;code&gt;feat&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;or an emoji (&lt;code&gt;lipstick&lt;/code&gt; 💄) and a prefix amongst a short list of relevant prefixes (e.g. &lt;code&gt;feat&lt;/code&gt; or &lt;code&gt;fix&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default mode is to start with the prefix selection. You can switch to emoji selection by pressing &lt;code&gt;[:]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you have both the prefix and the emoji, you can indicate if it's a breaking change.&lt;/p&gt;

&lt;p&gt;Afterward, the corresponding semantic version change is indicated (Major, Minor, Patch, None), and the commit message template is displayed. You can copy it to the clipboard by pressing &lt;code&gt;[Enter]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Behaviors
&lt;/h3&gt;

&lt;p&gt;The selection is made in various ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can navigate through the list of available choices, using the arrow keys &lt;code&gt;[↓]/[↑]&lt;/code&gt; to change the selected choice.&lt;/li&gt;
&lt;li&gt;And/or you can start typing the number of the choice to select (when numbers are displayed: for prefixes and emojis).&lt;/li&gt;
&lt;li&gt;And/or you can start typing some characters: the list of choices is filtered to match the input.

&lt;ul&gt;
&lt;li&gt;If a single choice matches the input, the step is auto-completed, the input is cleared, and you go to the next step.&lt;/li&gt;
&lt;li&gt;If multiple choices match:&lt;/li&gt;
&lt;li&gt;The portions that match the input are highlighted.&lt;/li&gt;
&lt;li&gt;You can complete the step by pressing &lt;code&gt;[Enter]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The search is case-insensitive, and has 2 modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick search: the input is matched against the beginning of the choice code.&lt;/li&gt;
&lt;li&gt;Full-text search: the input is matched against the whole choice text.&lt;/li&gt;
&lt;li&gt;You can switch to full-text search by pressing &lt;code&gt;[Alt]+[F]&lt;/code&gt; (or &lt;code&gt;[Ctrl]+[F]&lt;/code&gt; when it's not intercepted by the host).&lt;/li&gt;
&lt;li&gt;You can exit the full-text search by pressing &lt;code&gt;[Alt]+[F]&lt;/code&gt; again (or &lt;code&gt;[Escape]&lt;/code&gt; when it's not intercepted by the host).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 In the quick search mode, if your input matches nothing, the mode is automatically expanded to full-text and a new search is performed. You will the new matches, if any. If not, the mode will automatically return to quick search mode.&lt;/p&gt;

&lt;p&gt;At any time, you can press:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[Alt]+[Z]&lt;/code&gt; or &lt;code&gt;[Backspace]&lt;/code&gt; to undo the last action (if any).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[Ctrl]+[C]&lt;/code&gt; to close the tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 These keystrokes are indicated in the hints panel that is updated to match the input and the selection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Commitji bridges the gap between Conventional Commit, Gitmoji and Semantic Release to give us the very best in commit message quality. It's a micro-tool that doesn't seek to replace our usual tools, but rather to complement them.&lt;/p&gt;

&lt;p&gt;It offers a single functionality, but in the most user-friendly way possible for a command-line tool. It also has the advantage of being optional: once you've used it for a while, you won't need it as long as you know how to write your commit messages in the right format, meaning with the right combination of a prefix, an emoji and an eventual breaking change. But it's still readily available in case of doubt.&lt;/p&gt;

&lt;p&gt;💡 For the more curious, &lt;em&gt;Commitji&lt;/em&gt; is written in F# to follow the functional programming principles, including the &lt;a href="https://elmish.github.io/elmish/" rel="noopener noreferrer"&gt;Elmish&lt;/a&gt; MVU pattern. It relies on &lt;a href="https://spectreconsole.net/" rel="noopener noreferrer"&gt;Spectre.Console&lt;/a&gt;, a great library in particular for rendering in a command terminal.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://github.com/rdeneau/commitji/" rel="noopener noreferrer"&gt;Source code on GitHub&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Edit
&lt;/h2&gt;

&lt;p&gt;⚠️ I realized later that &lt;strong&gt;Commitji&lt;/strong&gt; also refers to a &lt;a href="https://marketplace.visualstudio.com/items?itemName=jmaicaaan.commitji-vs" rel="noopener noreferrer"&gt;Visual Studio Code extension&lt;/a&gt; that fortunately does roughly the same thing: the extension is light and fast, while the dotnet tool is more strict and covers more cases, which takes more keyboard strokes...&lt;/p&gt;

&lt;p&gt;Sorry for the confusion of using the name of an existing tool 😓, which I would have avoided if I had known beforehand. Be free to test both tools.&lt;/p&gt;

</description>
      <category>commit</category>
      <category>git</category>
      <category>dotnet</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
