thinkbeforecoding 2021-12-17T08:55:54.2019611+00:00 Jérémie Chassaing urn:md5:18477 F# script Functional Event Sourcing Decider urn:md5:e4eeeb768253d048be6d fa329b3b97f 2021-12-17T08:55:54.2019611+00:00 Jérémie Chassaing <p><em>this post is part of the <a href="https://sergeytihon.com/2021/10/18/f-advent-calendar-2021/">F# Advent Calendar 2021</a></em></p> <p>After years of talks and workshops about Functional Event Sourcing, I noticed that I published only 4 posts on the topic.</p> <p>The first is a <a href="/post/2013/07/28/Event-Sourcing-vs-Command-Sourcing">rant in 2013</a> about <a href="https://www.martinfowler.com/eaaDev/EventSourcing.html">Martin Fowler's article from 2005</a> describing something that could be called Command Sourcing and is misleading people into thinking they are doing Event Sourcing.</p> <p>The second is a <a href="/post/2014/01/04/Event-Sourcing.-Draw-it">simple drawing</a> describing the flow of Functional Event Sourcing. Really useful, many people told me something clicked once they saw this picture. But still a bit short. I made a few wording changes since then.</p> <p>I then made two posts about <a href="/post/2014/04/11/Monoidal-Event-Sourcing">Monoidal</a> <a href="/post/2014/04/27/Monoidal-Event-Sourcing-Examples">Event Sourcing</a> trying theoretical ideas to change this <a href="http://thinkbeforecoding.github.io/FsUno.Prod/Dynamical%20Systems.html">external monoid</a> to a plain monoid.</p> <p>It was accompanied by many samples on github, such as the various <a href="https://github.com/thinkbeforecoding/UnoCore">FsUno</a> implementations, the <a href="https://github.com/thinkbeforecoding/hackyourjob-crazyeights">crazyeights</a> workshop as well as the source code of <a href="https://github.com/thinkbeforecoding/crazy">Crazy Farmers</a>' port for <a href="https://boardgamearena.com/gamepanel?game=crazyfarmers">Board Game Arena</a> that uses both Server Side and Client Side event sourcing -- the client side being transpiled to JS using Fable, and the server side to PHP using peeble.</p> <p>I'm currently working on a book about it, but writing books takes time. And digging deep into the topic led me to discover new things that make it even longer to write.</p> <p>So here it is, a beginner's introduction to Functional Event Sourcing and its main pattern, the Decider.</p> <h2><a name="Anatomy-of-a-Service" class="anchor" href="#Anatomy-of-a-Service">Anatomy of a Service</a></h2> <p>Let's look at a System. Any System.</p> <p>Without interactions with the outside, such a system would be pretty useless. We can represent these interactions in a generic way as inputs and outputs</p> <p><img src="/public/functional-event-sourcing-decider/diagram-0.svg" alt="Diagram" /></p> <p>A system that accepts inputs but produces no outputs would be a kind of black hole.</p> <p><img src="/public/functional-event-sourcing-decider/diagram-1.svg" alt="Diagram" /></p> <p>this is not totally useless (cf /dev/null), but quite limited.</p> <p>On the other hand, a system that produces outputs without inputs seems also very simplistic. Without introducing time, it would necessarily be a constant:</p> <p><img src="/public/functional-event-sourcing-decider/diagram-2.svg" alt="Diagram" /></p> <p>So, let's introduce time; let's add a clock to our system:</p> <p><img src="/public/functional-event-sourcing-decider/diagram-3.svg" alt="Diagram" /></p> <p>The problem with a clock is that it's (obviously) changing over time, so let's refactor to treat clock as an input (it also becomes a trigger):</p> <p><img src="/public/functional-event-sourcing-decider/diagram-4.svg" alt="Diagram" /></p> <p>Here, our system is a pure function of time. This can be useful; however, most of the systems we deal with are a bit more complicated.</p> <p>As we wanted interactions, we can reintroduce inputs as triggers. For instance a user action.</p> <p><img src="/public/functional-event-sourcing-decider/diagram-5.svg" alt="Diagram" /></p> <p>To go back on the question of time, some time is passed in the system during code execution. But at today’s execution speed, especially outside of inputs/outputs, code execution can be considered as instant. To be executed the code needs some trigger to be called and run.</p> <p>A user action can be such a trigger, in this case, the current time can be seen as one parameter of the action.</p> <p>The trigger can also be the clock (a timer, an alarm..), but still the code is called for some reason (it's time for the Market to close, a check must be made every 5 minutes...). In this case, this is a scheduled automatic action, but it's still an action with current time as additional data.</p> <p>Most of the time, the output not only depends on the input action, but also on what happened before.</p> <p>The system needs a way to keep a trace of the effects of previous actions to react accordingly.</p> <p>Without such memory, the system is always reacting the same way to the same input action, regardless of anything that happened in the past. Some systems behave like this, but are a constrained case of more general systems that keep a trace of past actions.</p> <p>This memory is called state and is accessed and modified by the system code. It can be stored in memory (RAM) or saved to a database. Reading it can be considered a sort of input, changing it a sort of output:</p> <p><img src="/public/functional-event-sourcing-decider/diagram-6.svg" alt="Diagram" /></p> <p>This is a useful step. The subsystem can be cleared of a lot of technical concerns. The input interfaces can be abstracted (HTTP API, message queue, UI events, command line arguments, timers or alarms...) and parameters can be passed to the subsystem directly. The output interaction can also be abstracted and hidden behind interfaces (Outbound HTTP calls, messages or notification sending...). State loading and saving can also be hidden behind an interface to protect the subsystem from implementation details.</p> <p>Once carefully stripped of technical concerns, the code in the subsystem is merely composed of the system logic; what we commonly call the business logic, or the Domain. We call the rest of the code the Application layer.</p> <p>We described here the hexagonal architecture where the application core and the Domain are loosely coupled to their environment through port interfaces, implemented as adapters to the technical infrastructure.</p> <h2><a name="Functional-Core" class="anchor" href="#Functional-Core">Functional Core</a></h2> <p>We can go a bit further by applying <a href="/post/2018/01/25/functional-core">Functional Core</a> to our model. The idea is to write the Subsystem as a pure function.</p> <p>The input Actions and Clock will be passed as input values (the current time, if needed, in the case of the clock). Actually we can consider current time as being a parameter of the action, and will not mention it again.</p> <p>For state, we can also load its current value, and pass it to the function. The function will return a new state that can be stored.</p> <p>Outputs and side effects can also be returned as values by the functions, and the side effects will be performed by the application layer:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '5', 8)" onmouseover="showTip(event, '5', 8)" class="fn">subsystem</span> <span class="pn">(</span><span onmouseout="hideTip(event, '6', 9)" onmouseover="showTip(event, '6', 9)" class="fn">action</span><span class="pn">:</span> <span onmouseout="hideTip(event, '2', 10)" onmouseover="showTip(event, '2', 10)" class="rt">Action</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '7', 11)" onmouseover="showTip(event, '7', 11)" class="fn">state</span><span class="pn">:</span> <span onmouseout="hideTip(event, '3', 12)" onmouseover="showTip(event, '3', 12)" class="rt">State</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '3', 13)" onmouseover="showTip(event, '3', 13)" class="rt">State</span> <span class="pn">*</span> <span onmouseout="hideTip(event, '4', 14)" onmouseover="showTip(event, '4', 14)" class="rt">Output</span> <span onmouseout="hideTip(event, '8', 15)" onmouseover="showTip(event, '8', 15)" class="rt">list</span> <span class="o">=</span> <span onmouseout="hideTip(event, '7', 16)" onmouseover="showTip(event, '7', 16)" class="fn">state</span><span class="pn">,</span> <span class="pn">[</span><span class="pn">]</span> </code></pre> <p>This is here, obviously a system that does nothing. By returning a new state, it will be persisted for the next call, and by returning output, it will be able to product other side effects.</p> <h2><a name="Actions-and-Commands" class="anchor" href="#Actions-and-Commands">Actions and Commands</a></h2> <p>The Functional Core Domain is called on external triggers we called Actions. We can split them initially into two groups we'll call Commands and Events.</p> <p>A command is an action on the system with an intention to change it. A user places an order, cancels a subscription or books a hotel room. It can succeed or fail, but should have an effect on the system.</p> <p>On the other side, something can happen outside of the system that should have an effect on it. The weather changed, a customer checked out, a cargo left a harbor, a scheduled alarm expired. Those things happened and there's nothing we can do to change the fact. This can trigger a change in the system. We call them External Events.</p> <p>Our Functional Core domain could directly take External Events as an input, be we can find in the Domain internal Commands associated. The WeatherChanged event leads to a PrepareForRain command. It's 4PM, the market bell rang; that's a CloseMarket command.</p> <p>In the same way, in user interface code, it is advised to not take action directly in event handler's code. In the onButtonClicked function, it is better to call another DoAction() function that does the actual action. The code is clearer and the action can then be called on different triggers, and just tested without having to raise the event itself.</p> <p>There is also a distinction between External Commands and Internal Commands. Current time can be important to process a command, and will be part of input data. However, current time will not be provided by the Command sender as that would be highly unsafe: caller could ante/postdate the Command. The External Command is instead enriched with current time in the Application layer. Similarly for external data such as exchange rates, weather conditions or resources protected by access rights. Caller identity should also be used with care, it can be either validated using a password, access-key, signature or a login check.</p> <p>We will now consider any Domain input action as an internal Command containing all enrichment data and call it a Command for brevity. A Command can be implemented as a data structure with a name indicating its intent and containing the associated data. Its name is always a verb phrase in the imperative tense.</p> <h2><a name="Decision" class="anchor" href="#Decision">Decision</a></h2> <p>The next step is to look inside the Functional Core Domain and split it even further.</p> <p>It's a pure function that takes a Command and current State, and returns a State and some Outputs.</p> <p>The typical way to proceed in fulfilling a Command given current State is to modify State according to business rules. The code checks what the situation is and follows the rules defined by the domain to modify the State in a consistent way.</p> <p>Doing this, we're going a bit too fast. We take some shortcuts. We take decisions and apply the effects of these decisions at the same time. These are two quite different steps, and conflating them obscures the actual decision process.</p> <p>Leaving the decision process implicit proves to be problematic. Looking at data, the business is wondering why we ended up in the current state. Is it a bug, or did a legitimate chain of actions produce this unexpected result? Tracing back observable side effects and saved intermediate state is time consuming and cannot always give definitive answers.</p> <h3><a name="Against-logging" class="anchor" href="#Against-logging">Against logging</a></h3> <p>This often leads to bloating the code with logs. Logs are initially useful, but they don't age well. They are added on second thought, and seldom tested. Like commands, after a few refactorings, they most often end up outdated, reporting incorrect and/or partial traces. Having up correct logging in sync with the model requires a lot of care. The first slip in that care erodes trust in the traces. This quickly becomes a time hog during diagnosis. Especially when unexpected cases happen, everything needs to be double checked, in the traces and in the code that may have changed in-between.</p> <p>As an afterthought, their operation is also not designed with care. Log retention is costly, and choosing the right log level is difficult. Too verbose, and the expense of log storage can become prohibitive, forcing a short retention period. Not verbose enough, and critical information can be missing. Cleaning logs is also difficult because not all logs are of equal importance, nor is everything equally relevant over the same timespan. Sadly, log systems rarely give much flexibility in the cleaning/archiving process. All this becomes useless anyway if the log cannot be trusted.</p> <h3><a name="Events" class="anchor" href="#Events">Events</a></h3> <p>To avoid these conflicts, we untangle decision making from the changing of the state. We'll be explicit about what happens by materializing decision outcomes before changing state, and changing state based only on the decision outcome data.</p> <p>We can express these Commands processing outcomes as Events. Each one expresses what just happened to the system as a past tense verb, which then leads to a new state.</p> <p>A Switch Light On Command will, if valid, produce a Light Switched On Event. A Transfer Money Command will produce a Money Transferred Event, or a Money Transfer Rejected Event due to insufficient funds.</p> <p>A Decision process then takes this simple form:</p> <p><img src="/public/functional-event-sourcing-decider/diagram-7.svg" alt="Diagram" /></p> <p>If we use simple data structures for Commands, State and Events, the decision can be implemented as a function with the following signature:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '11', 21)" onmouseover="showTip(event, '11', 21)" class="fn">Decide</span> <span class="o">=</span> <span onmouseout="hideTip(event, '9', 22)" onmouseover="showTip(event, '9', 22)" class="rt">Command</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '3', 23)" onmouseover="showTip(event, '3', 23)" class="rt">State</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '10', 24)" onmouseover="showTip(event, '10', 24)" class="rt">Event</span> <span onmouseout="hideTip(event, '8', 25)" onmouseover="showTip(event, '8', 25)" class="rt">list</span> </code></pre> <p>Since we decided to not modify state at this stage, the State can be immutable (read only), as the Commands and Events should also be.</p> <p>This function has no reason to produce any side effects, such as reading or writing external state, or calling external services. We've seen how to deal with external data like current time or exchange rates already. So it can be implemented as a <strong>pure function</strong>:</p> <ul> <li>Its return value should depend only on the input parameters</li> <li>It should not produce any noticeable external side effect.</li> </ul> <p>The first point is really interesting for testing and reasoning about the code. Given a current State and a Command, the resulting Event list is always identical. This is true whatever the day and time and whatever the current state anywhere else. It eases the testing as they will never be dependent on external concerns. It also eases debugging; if we logged the Command data and have a way to know the State at that point in time - which we’ll do - there is only a single possible outcome. This forces us to not depend on any external data that is not already in State or Command parameters, such as current time or external data retrieval.</p> <p>The second point stems from our choice to make decisions outcomes explicit. If the function produces any side effect, that breaks our principle of first expressing the decision made before applying any change. We’ll also see why even logging is useless inside this function.</p> <p>These constraints give rise to many interesting properties.</p> <p>In summary, a decision function is a way to write:</p> <table class="pre"><tr><td class="snippet"><pre class="fssnip"><code lang="txt">When asked to process this Command in a given State, here is what happens, expressed as Events. </code></pre></td></tr></table> <h2><a name="Evolution" class="anchor" href="#Evolution">Evolution</a></h2> <p>We’ve decided to split taking a decision and applying the resulting changes. The goal was to make the actual decision taken more explicit in the code base. So, in the previous part, we devised a Decide function that returns Events but does not actually change State. Now, let’s see how to capture change in a simple and highly testable way. This will actually be quite straight forward.</p> <p>To compute the new State, we need the current State and the Event that just happened.</p> <p>We could modify the current State, mutating it so it becomes the new State, but this is not how we’ll proceed. Mutation will not automatically lead you to bad code and bugs, but we can consider it a premature optimization at this point. If you’re not familiar with Functional Programming, immutability can seem very costly and inefficient (and this can be correct in some contexts). But most modern languages, functional or not, are fast enough in immutable scenarios compared to querying a database or making a network call. The result is that the overhead of immutability at the level of Domain code can often be ignored. We’ll see how using immutable data structures for State enables reasoning about the code, and how it has interesting composition properties. So let’s proceed with immutable State, and you’ll decide your implementation strategy based on your own stack constraints later.</p> <p>Earlier, our Decision function was returning an Event list containing zero, one or more events. We will focus first on how to deal with a single Event. It will be easy to extend from there to handling multiple events.</p> <p>With immutable read only State data structures and read only Events, it becomes obvious that computing new State will also be implemented as a pure function. There is no way to change the supplied current State and Event; they are read only. The Event and the State must contain all the data we need, so there is no point fetching data from somewhere else. No external service calls. In that structure, mutating data outside would be akin to using global state, which would defeat the purpose of all this. We have all the required data at hand, and just have to compute the new State to return it. We’ll see further that there is also no reason for things like logging or tracing in this code.</p> <p>Let’s call this function evolve; its signature is:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '12', 26)" onmouseover="showTip(event, '12', 26)" class="fn">Evolve</span> <span class="o">=</span> <span onmouseout="hideTip(event, '3', 27)" onmouseover="showTip(event, '3', 27)" class="rt">State</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '10', 28)" onmouseover="showTip(event, '10', 28)" class="rt">Event</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '3', 29)" onmouseover="showTip(event, '3', 29)" class="rt">State</span> </code></pre> <p>It takes a State and an Event and returns a State. Its meaning is: Given a current State, when Event occurs, here is the new State.</p> <p>The code of the evolve function should be extremely simple; the Decision has already been taken. It should probably not be more that setting a field, adding a element to a list, incrementing a value, or setting/resetting a flag.</p> <p>The evolve function is central to Event Sourcing but will rarely be more complicated than a few lines of codes.</p> <h2><a name="Initial-State" class="anchor" href="#Initial-State">Initial State</a></h2> <p>For the first Command, we find ourselves in a specific situation. We have a Command and a decide function. But the decide function needs an input state, and we have no State yet that we can pass as a parameter. It's the same situation with the evolve function on the first Event.</p> <p>If we consider the state returned by the evolve function and this first Event, we can obviously say that it's the State after the first Event occurs. So the input state is the State before the first Event occurs, when nothing occurred yet. We will call this the Initial State.</p> <p>The Initial State is important as it has to be explicitly defined. Sometimes we may opt to use a possible future State for it. For a light, for instance, it could be On or Off. For an account, it could be defined with a 0 balance. It will just use specific values for the properties, and it is totally possible that it will be back in the same state later. The light will be Off again, and the account could return to a 0 balance in the future.</p> <p>However, the first Event is sometimes irreversible. For a card game, before the first event happens, the game is not yet started. After the first event, it is started. It will eventually end, but will not return to the "not started yet state" anymore. This situation often arises when some initial properties have to be defined; some initial actions sets the system up. In a card game, the dealer will place the first card on the table. This is an action that can only happen at the beginning, it's the game setup. It marks the actual start of the game; before that, no other action can take place.</p> <p>In this case, the initial State has no other purpose than representing that we are ready to handle the initial action. It doesn't need to contain more information. It is easy to represent such state in languages with sum types or discriminated unions:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '14', 32)" onmouseover="showTip(event, '14', 32)" class="rt">State</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">InitialState</span> <span class="pn">|</span> <span class="uc">Started</span> <span class="k">of</span> <span class="prop">topCard</span><span class="pn">:</span> <span onmouseout="hideTip(event, '13', 33)" onmouseover="showTip(event, '13', 33)" class="rt">Card</span> <span class="k">let</span> <span onmouseout="hideTip(event, '15', 34)" onmouseover="showTip(event, '15', 34)" class="id">initialState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '16', 35)" onmouseover="showTip(event, '16', 35)" class="uc">InitialState</span> </code></pre> <p>This indicates that the state is always either a) InitialState (without any more information), or b) the game is in progress, with the specified card on top of the pile.</p> <p>In languages without sum types, we'll usually use a boolean or enum value to mark the difference:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '17', 36)" onmouseover="showTip(event, '17', 36)" class="rt">State</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Started</span><span class="pn">:</span> <span onmouseout="hideTip(event, '18', 37)" onmouseover="showTip(event, '18', 37)" class="vt">bool</span> <span class="prop">TopCard</span><span class="pn">:</span> <span onmouseout="hideTip(event, '13', 38)" onmouseover="showTip(event, '13', 38)" class="rt">Card</span><span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '15', 39)" onmouseover="showTip(event, '15', 39)" class="id">initialState</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Started</span> <span class="o">=</span> <span class="k">false</span> <span class="prop">TopCard</span> <span class="o">=</span> <span onmouseout="hideTip(event, '19', 40)" onmouseover="showTip(event, '19', 40)" class="m">Unchecked</span><span class="pn">.</span><span onmouseout="hideTip(event, '20', 41)" onmouseover="showTip(event, '20', 41)" class="id">defaultof</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '13', 42)" onmouseover="showTip(event, '13', 42)" class="rt">Card</span><span class="pn">&gt;</span> <span class="pn">}</span> </code></pre> <p>You can notice here that two problems arise. First, we have to be careful not to use the TopCard property when Started is false. Should we use an exception or a similar error mechanism to prevent this from happening? Probably, but it would be far better to not be able to write such code in the first place. Second, what is a good value for TopCard in the initial state when Started is false? Here I chose a three of clubs, which seems a bit arbitrary; but any value would be. There is no good value of the Card type that naturally represents a default value. In some languages, an option might be to use null, but this is also dangerous if null is never a valid value once started. Null Reference Exceptions are frequent errors that are better avoided from the start. If we are prepared to use null, the next option would be to use it and get rid of Started altogether.</p> <p>On the pro side, this makes state more compact, and avoids requiring a check on a property to know if the other is valid, potentially leading to consistency problems. On the con side, the initial state is less explicit. The code doesn’t clearly express when it is valid to have a TopCard or not.</p> <h2><a name="Stitching-it-together" class="anchor" href="#Stitching-it-together">Stitching it together</a></h2> <p>Now we have all the parts needed for Event Sourcing. Let's put them together. We described three types and three elements in the previous sections, with the following signatures:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '21', 43)" onmouseover="showTip(event, '21', 43)" class="rt">Command</span> <span class="k">type</span> <span onmouseout="hideTip(event, '22', 44)" onmouseover="showTip(event, '22', 44)" class="rt">Event</span> <span class="k">type</span> <span onmouseout="hideTip(event, '23', 45)" onmouseover="showTip(event, '23', 45)" class="rt">State</span> <span class="id">initialState</span><span class="pn">:</span> <span onmouseout="hideTip(event, '23', 46)" onmouseover="showTip(event, '23', 46)" class="id">State</span> <span class="id">decide</span><span class="pn">:</span> <span onmouseout="hideTip(event, '21', 47)" onmouseover="showTip(event, '21', 47)" class="id">Command</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '23', 48)" onmouseover="showTip(event, '23', 48)" class="id">State</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '22', 49)" onmouseover="showTip(event, '22', 49)" class="id">Event</span> <span onmouseout="hideTip(event, '8', 50)" onmouseover="showTip(event, '8', 50)" class="id">list</span> <span class="id">evolve</span><span class="pn">:</span> <span onmouseout="hideTip(event, '23', 51)" onmouseover="showTip(event, '23', 51)" class="id">State</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '22', 52)" onmouseover="showTip(event, '22', 52)" class="id">Event</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '23', 53)" onmouseover="showTip(event, '23', 53)" class="id">State</span> </code></pre> <p>The Command will come from the outside, but the State and Event list will be fed from the decide function output to the evolve function input while the output State from the evolve function will be passed to the next call to the decide function. The same output State will also be used as an input parameter for the next call to the evolve function.</p> <p><img src="/public/functional-event-sourcing-decider/diagram-8.svg" alt="Diagram" /></p> <p>When processing in the system begins, it is in the Initial State. For now, nothing has happened yet.</p> <p>When the first command arrives, we have a Command and a State that we can pass to the decide function. It will return the outcomes of the Command as a list of Events: the things that happened in reaction to the input Command.</p> <p>If the output Event list is empty, nothing happened; there's no need to compute a new state and we are ready for the next Command. This should not happen frequently for at least two reasons. A system that does mostly nothing is not very interesting and can probably be implemented without Event Sourcing... But doing nothing can also make some situations harder to diagnose. When a Command was intended to do something but resulted in no change, it can be interesting to know the reasons. Emitting no Events will make the distinction between an infrastructure problem and a motivated decision to do nothing harder to find. Did the system crash, or did it just decide to do nothing?</p> <p>It is still possible to know by taking a copy of the Command that has been persisted for diagnostic purposes, and a State reconstructed from past Events, passing them to the decide function and examining the result, but it will require careful code analysis or creating a new test with this specific data. This drains developers time and is better avoided.</p> <p>If the decision to do nothing results from a business rule, it is advised to make it explicit, returning an Event that will not affect State. It will clearly appear in the produced Events and diagnostics will be trivial. This validation can be done by support teams without any access to the code.</p> <p>However, if nothing happened simply because we are already in some expected state, that's a case of an idempotent Command. In such cases, it is actually better to return no Events. This avoids bloating the Event Store with useless duplicate Events.</p> <p>When the Event list contains an Event, we can call the evolve function with current State and that Event. The resulting new State is then used for the next Command instead of the Initial State.</p> <p>Sometimes the Event list will contain several Events. In this case we will call the evolve function for each Event, passing previous computed State along.</p> <p>This could give something like:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="id">newState1</span> <span class="o">=</span> <span class="id">evolve</span> <span class="id">currentState</span> <span class="id">event1</span> <span class="k">let</span> <span class="id">newState2</span> <span class="o">=</span> <span class="id">evolve</span> <span class="id">newState1</span> <span class="id">event2</span> <span class="k">let</span> <span class="id">newState3</span> <span class="o">=</span> <span class="id">evolve</span> <span class="id">newState2</span> <span class="id">event3</span> </code></pre> <p>We can do better, but we now have the next current State and we are ready to process the next Command.</p> <h2><a name="Fold" class="anchor" href="#Fold">Fold</a></h2> <p>When we have several events, we have to call the evolve function for each.</p> <p>A simple way to do that is to use a loop:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '27', 61)" onmouseover="showTip(event, '27', 61)" class="fn">computeNextState</span> <span onmouseout="hideTip(event, '28', 62)" onmouseover="showTip(event, '28', 62)" class="fn">currentState</span> <span onmouseout="hideTip(event, '29', 63)" onmouseover="showTip(event, '29', 63)" class="fn">events</span> <span class="o">=</span> <span class="k">let</span> <span class="k">mutable</span> <span onmouseout="hideTip(event, '30', 64)" onmouseover="showTip(event, '30', 64)" class="mv">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '28', 65)" onmouseover="showTip(event, '28', 65)" class="fn">currentState</span> <span class="k">for</span> <span onmouseout="hideTip(event, '25', 66)" onmouseover="showTip(event, '25', 66)" class="fn">event</span> <span class="k">in</span> <span onmouseout="hideTip(event, '29', 67)" onmouseover="showTip(event, '29', 67)" class="fn">events</span> <span class="k">do</span> <span onmouseout="hideTip(event, '30', 68)" onmouseover="showTip(event, '30', 68)" class="mv">state</span> <span class="k">&lt;-</span> <span onmouseout="hideTip(event, '24', 69)" onmouseover="showTip(event, '24', 69)" class="fn">evolve</span> <span onmouseout="hideTip(event, '30', 70)" onmouseover="showTip(event, '30', 70)" class="mv">state</span> <span onmouseout="hideTip(event, '25', 71)" onmouseover="showTip(event, '25', 71)" class="fn">event</span> <span onmouseout="hideTip(event, '30', 72)" onmouseover="showTip(event, '30', 72)" class="mv">state</span> </code></pre> <p>As you can see, F# makes mutability explicit through the mutable keyword. Without it, state cannot be changed to a new value... It also uses this backward looking left arrow <code>&lt;-</code> which seems to suggest that we're going in the wrong direction. F# IDEs also tend to display mutable variables in orange to signal them as a kind of warning...</p> <p>Another way to proceed without mutation is to use a recursive function that we will call fold:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '31', 73)" onmouseover="showTip(event, '31', 73)" class="fn">fold</span> <span onmouseout="hideTip(event, '7', 74)" onmouseover="showTip(event, '7', 74)" class="fn">state</span> <span onmouseout="hideTip(event, '32', 75)" onmouseover="showTip(event, '32', 75)" class="fn">events</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '32', 76)" onmouseover="showTip(event, '32', 76)" class="fn">events</span> <span class="k">with</span> <span class="pn">|</span> <span class="pn">[</span><span class="pn">]</span> <span class="k">-&gt;</span> <span class="c">// there are no events..</span> <span onmouseout="hideTip(event, '7', 77)" onmouseover="showTip(event, '7', 77)" class="fn">state</span> <span class="c">// nothing changed</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '25', 78)" onmouseover="showTip(event, '25', 78)" class="fn">event</span> <span class="uc">::</span> <span onmouseout="hideTip(event, '33', 79)" onmouseover="showTip(event, '33', 79)" class="fn">rest</span> <span class="k">-&gt;</span> <span class="c">// compute state after first event</span> <span class="k">let</span> <span onmouseout="hideTip(event, '34', 80)" onmouseover="showTip(event, '34', 80)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '24', 81)" onmouseover="showTip(event, '24', 81)" class="fn">evolve</span> <span onmouseout="hideTip(event, '7', 82)" onmouseover="showTip(event, '7', 82)" class="fn">state</span> <span onmouseout="hideTip(event, '25', 83)" onmouseover="showTip(event, '25', 83)" class="fn">event</span> <span class="c">// do it again with next events</span> <span onmouseout="hideTip(event, '31', 84)" onmouseover="showTip(event, '31', 84)" class="fn">fold</span> <span onmouseout="hideTip(event, '34', 85)" onmouseover="showTip(event, '34', 85)" class="fn">newState</span> <span onmouseout="hideTip(event, '33', 86)" onmouseover="showTip(event, '33', 86)" class="fn">rest</span> </code></pre> <p>When the list is empty [] we just return the input state. When the list is not empty, we deconstruct the list as event :: rest, event is first Event, and rest is rest of the list. We can then compute the new intermediate State using evolve and call fold again with this newState and the remaining events rest, until we have applied them all.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '35', 87)" onmouseover="showTip(event, '35', 87)" class="fn">fld</span> <span onmouseout="hideTip(event, '36', 88)" onmouseover="showTip(event, '36', 88)" class="fn">f</span> <span onmouseout="hideTip(event, '37', 89)" onmouseover="showTip(event, '37', 89)" class="fn">s</span> <span onmouseout="hideTip(event, '38', 90)" onmouseover="showTip(event, '38', 90)" class="fn">es</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '38', 91)" onmouseover="showTip(event, '38', 91)" class="fn">es</span> <span class="k">with</span> <span class="pn">|</span><span class="pn">[</span><span class="pn">]</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '37', 92)" onmouseover="showTip(event, '37', 92)" class="fn">s</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '39', 93)" onmouseover="showTip(event, '39', 93)" class="fn">e</span> <span class="uc">::</span> <span onmouseout="hideTip(event, '38', 94)" onmouseover="showTip(event, '38', 94)" class="fn">es</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '40', 95)" onmouseover="showTip(event, '40', 95)" class="fn">ns</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 96)" onmouseover="showTip(event, '36', 96)" class="fn">f</span> <span onmouseout="hideTip(event, '37', 97)" onmouseover="showTip(event, '37', 97)" class="fn">s</span> <span onmouseout="hideTip(event, '39', 98)" onmouseover="showTip(event, '39', 98)" class="fn">e</span> <span onmouseout="hideTip(event, '35', 99)" onmouseover="showTip(event, '35', 99)" class="fn">fld</span> <span onmouseout="hideTip(event, '36', 100)" onmouseover="showTip(event, '36', 100)" class="fn">f</span> <span onmouseout="hideTip(event, '40', 101)" onmouseover="showTip(event, '40', 101)" class="fn">ns</span> <span onmouseout="hideTip(event, '38', 102)" onmouseover="showTip(event, '38', 102)" class="fn">es</span> </code></pre> <p>Most languages provide libraries containing an implementation of this function. It is called fold, left fold or aggregate. It takes a list, an aggregation function, and an initial value. It calls the aggregation function for each item in the list with this item and previous result. In F# its signature is:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span onmouseout="hideTip(event, '41', 103)" onmouseover="showTip(event, '41', 103)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 104)" onmouseover="showTip(event, '42', 104)" class="id">fold</span><span class="pn">:</span> <span class="pn">(</span><span class="id">&#39;</span><span class="id">s</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">e</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">s</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">s</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">e</span> <span onmouseout="hideTip(event, '8', 105)" onmouseover="showTip(event, '8', 105)" class="id">list</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">s</span> </code></pre> <p>It seems a bit cryptic at first, but bear with me. The tick (') marks generic type names that can be any actual type. The only constraint is that all 's should have the same type, and same thing for all 'e. The first argument is a 's -&gt; 'e -&gt; 's - a function that takes a 's and an 'e and returns a 's. We can notice that it’s the same form as our evolve function when replacing 's with State and 'e with Event. The second argument is a 's, in our case a State. That's the initial value. The 'e list in our case is the Event list. Finally, the result is a 's, which will be a State.</p> <p>Computing a new state after events when initially in a given state is simply:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="id">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 106)" onmouseover="showTip(event, '41', 106)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 107)" onmouseover="showTip(event, '42', 107)" class="id">fold</span> <span class="id">evolve</span> <span class="id">state</span> <span class="id">events</span> </code></pre> <p>It will work as expected with no event in the list, in which case it will return the input state. It will also process a single event as we did by calling the evolve function once.</p> <p>The nice thing it that it is also useful for rebuilding the current State from the Initial State and the full list of Events that happened:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="id">currentState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 108)" onmouseover="showTip(event, '41', 108)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 109)" onmouseover="showTip(event, '42', 109)" class="id">fold</span> <span class="id">evolve</span> <span class="id">initialState</span> <span class="id">events</span> </code></pre> <p>This is exactly what we’ll need when restarting the system from a persisted Event Log.</p> <h2><a name="Or-not-fold" class="anchor" href="#Or-not-fold">Or not fold</a></h2> <p>While the previous description represents a vast majority of event sourced systems, we should still consider a possibility that could be useful in some cases.</p> <p>It would be totally legit to use the following evolve function:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '23', 110)" onmouseover="showTip(event, '23', 110)" class="id">State</span> <span class="o">=</span> <span onmouseout="hideTip(event, '22', 111)" onmouseover="showTip(event, '22', 111)" class="id">Event</span> <span onmouseout="hideTip(event, '8', 112)" onmouseover="showTip(event, '8', 112)" class="id">list</span> <span class="k">let</span> <span class="id">initialState</span> <span class="o">=</span> <span class="pn">[</span><span class="pn">]</span> <span class="k">let</span> <span class="id">evolve</span> <span class="id">state</span> <span class="pn">(</span><span class="id">event</span><span class="pn">:</span> <span onmouseout="hideTip(event, '22', 113)" onmouseover="showTip(event, '22', 113)" class="id">Event</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 114)" onmouseover="showTip(event, '41', 114)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '43', 115)" onmouseover="showTip(event, '43', 115)" class="id">append</span> <span class="id">state</span> <span class="pn">[</span><span class="id">event</span><span class="pn">]</span> </code></pre> <p>The state would then just be the full list of all events that happened so far. That would definitely contain all the information needed by the decide function:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="id">decide</span> <span class="id">command</span> <span class="pn">(</span><span class="id">state</span><span class="pn">:</span> <span onmouseout="hideTip(event, '22', 116)" onmouseover="showTip(event, '22', 116)" class="id">Event</span> <span onmouseout="hideTip(event, '8', 117)" onmouseover="showTip(event, '8', 117)" class="id">list</span><span class="pn">)</span> <span class="o">=</span> <span class="c">(* ... *)</span> </code></pre> <p>This decide function can now work through the event list to find relevant data to take decision.</p> <p>Once going this direction, the evolve function looks rather useless. Folding the state would look like:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">events</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '41', 118)" onmouseover="showTip(event, '41', 118)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 119)" onmouseover="showTip(event, '42', 119)" class="id">fold</span> <span class="id">evolve</span> <span class="id">initialState</span> </code></pre> <p>Which is equivalent to:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">events</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '41', 120)" onmouseover="showTip(event, '41', 120)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 121)" onmouseover="showTip(event, '42', 121)" class="id">fold</span> <span class="pn">(</span><span class="k">fun</span> <span class="id">state</span> <span class="id">event</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '41', 122)" onmouseover="showTip(event, '41', 122)" class="id">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '43', 123)" onmouseover="showTip(event, '43', 123)" class="id">append</span> <span class="id">state</span> <span class="pn">[</span><span class="id">event</span><span class="pn">]</span><span class="pn">)</span> <span class="pn">[</span><span class="pn">]</span> </code></pre> <p>This rebuilds an exact copy of the initial events list! We can just pass the events list directly to the decide function.</p> <p>In that setting, there is just a decide function with the following signature:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">decide</span><span class="pn">:</span> <span onmouseout="hideTip(event, '21', 124)" onmouseover="showTip(event, '21', 124)" class="id">Command</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '22', 125)" onmouseover="showTip(event, '22', 125)" class="id">Event</span> <span onmouseout="hideTip(event, '8', 126)" onmouseover="showTip(event, '8', 126)" class="id">list</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '22', 127)" onmouseover="showTip(event, '22', 127)" class="id">Event</span> <span onmouseout="hideTip(event, '8', 128)" onmouseover="showTip(event, '8', 128)" class="id">list</span> </code></pre> <p>A function that takes a command and a list of Events and returns a list of new Events.</p> <p>There's no need for state nor an evolve function.</p> <p>This can definitely be of use in contexts with few events, or when performance doesn’t come into play.</p> <p>State built by the evolve function is just a projection to compact the information contained in the events to make it easier and/or faster for the decide function to take decisions. If it does not make it easier/faster, just use the raw event list.</p> <p>The full list of past Events is the form of the State that contains maximal information. This represents the full history.</p> <h2><a name="Terminal-State" class="anchor" href="#Terminal-State">Terminal State</a></h2> <p>For now our system has an Initial State to start, and the decide and evolve functions, to handle change over time.</p> <p>At first it seems enough, but this is due to one of our typical engineer’s bias… We’re very good at setting things up, but bad at disposing them. I’ve seen many systems where loads of data remained in the system mostly because nobody knew if it was safe to get rid of it.</p> <p>This can be seen in the industry at large. Mobile phones have been produced in astronomical numbers before realizing something should be done to dispose them properly, and this is still not handled by the manufacturers. Similarly for nuclear power plants that have not been designed considering how they can be dismantled.</p> <p>Whether you consider using event sourcing or not, it is best to consider this up front and explicitly design for disposal.</p> <p>Some things naturally have a definite lifetime. For instance, once an order has been shipped and every post shipment task have been processed, it should never change anymore. Same thing for a card game; when the game is over, the result can be taken into account for statistics etc, but the game will not change anymore, the decide function will never be called again.</p> <p>This can have many implications. For instance, if you keep state in memory for fast response, you can now unload it to save space. It also means that the history can be archived or deleted depending on your retention needs.</p> <p>Removing old data from your system (or at least moving it to a colder area) will keep your hot area slim and far more manageable. This is an efficient way to lower costs and simplify updates and migrations.</p> <p>Even parts that have a definite lifetime are sometimes hard to dispose. For instance, what happens when an order shipment was lost and there’s nobody to reclaim it? or where all players in a game left the table to never return? That could lead to data dangling forever. To avoid this, you have to determine a policy with domain experts. Appropriate solutions probably already exist in the domain. For instance, lost shipment cases are considered closed after 1 month in absence of reclamation. Or you could establish a new one. For a card game, players have a maximum time to play. That could range from a few hours for a real time game, to a few weeks for turn by turn. A process could be put in place to alert users, but after this delay a command is sent to the system to close it, and it then transitions to a terminal state.</p> <p>The question is more tricky for systems whose behavior can span continuously over many years with no foreseeable end. But this is something that has already been solved by accountants. Accounting records for a company can easily span decades. The current balance is impacted by all the records since the beginning, but it would be impractical to recompute everything from the first record. Especially after a few years, the relevance of such records to the current state drops significantly. This is where accountants define an accounting period. At the end of the period, a book balance is computed, and reconciled with the bank balances. The current book is closed and a new one is opened, starting from previous book balance. This way, once a book is closed, it is never changed anymore and can be archived for reference. If an error is found after closing the book, a compensation record is added in the current book.</p> <p>It is highly advised to put such mechanisms in place for your own system, especially if you keep data over time, like saving events. Even if storage is getting cheaper over time, your system will evolve, and since data that is considered hot can change at any time, it must be migrated and evolved in a transactional or high availability, zero downtime way. This places a high burden on operations. For streams of events, the time takes to recompute the current state with such strategy will depend on your business size. Without it, it will be dependent on both business size and time since it started (it’s actually an integral of business size over time).</p> <p>Once we’ve defined a condition for disposability, we can implement it with a simple function:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">IsTerminal</span><span class="pn">:</span> <span class="id">&#39;</span><span class="id">state</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '44', 129)" onmouseover="showTip(event, '44', 129)" class="id">bool</span> </code></pre> <p>This function takes a state, and returns a bool indicating if it is a terminal state. I really encourage you to make it part of your design to avoid maintenance problems later.</p> <h2><a name="Decider" class="anchor" href="#Decider">Decider</a></h2> <p>We’ve seen that State and the evolve function are just an optimization to compact information, to avoid going through the full list of Events at each call of the decide function. This clearly indicates that the most important part in what we’ve seen so far is the decide function.</p> <p>We will call a Decider the combination of the seven elements we’ve identified so far:</p> <ul> <li>A Command type that represents all commands that can be submitted to the Decider</li> <li>An Event type that represents all events that can be produced by the Decider</li> <li>A State type that represents all possible states of the Decider (can just be the list of all events)</li> <li>An Initial State that is the state of the Decider before anything happens</li> <li>A decide function that takes a Command and a State and returns a list of Event</li> <li>An evolve function that takes a State and an Event and returns a new State</li> <li>An isTerminal function that takes a State and returns a boolean value</li> </ul> <p>In F# this can be modeled as:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '45', 130)" onmouseover="showTip(event, '45', 130)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 131)" onmouseover="showTip(event, '46', 131)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 132)" onmouseover="showTip(event, '47', 132)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 133)" onmouseover="showTip(event, '48', 133)" class="id">s</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="fn">decide</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 134)" onmouseover="showTip(event, '46', 134)" class="id">c</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 135)" onmouseover="showTip(event, '48', 135)" class="id">s</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 136)" onmouseover="showTip(event, '47', 136)" class="id">e</span> <span onmouseout="hideTip(event, '8', 137)" onmouseover="showTip(event, '8', 137)" class="rt">list</span> <span onmouseout="hideTip(event, '24', 138)" onmouseover="showTip(event, '24', 138)" class="fn">evolve</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 139)" onmouseover="showTip(event, '48', 139)" class="id">s</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 140)" onmouseover="showTip(event, '47', 140)" class="id">e</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 141)" onmouseover="showTip(event, '48', 141)" class="id">s</span> <span class="prop">initialState</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 142)" onmouseover="showTip(event, '48', 142)" class="id">s</span> <span class="fn">isTerminal</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 143)" onmouseover="showTip(event, '48', 143)" class="id">s</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 144)" onmouseover="showTip(event, '18', 144)" class="vt">bool</span> <span class="pn">}</span> </code></pre> <p>The Decider is a conceptual way to think about systems that change in time; a concepty interface between the Application layer and the Domain code. It ensures extremely low friction between them.</p> <h2><a name="Run-in-memory" class="anchor" href="#Run-in-memory">Run in memory</a></h2> <p>We can easily make a decider run in memory on a mutable State variable:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">InMemory</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '49', 145)" onmouseover="showTip(event, '49', 145)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 146)" onmouseover="showTip(event, '50', 146)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 147)" onmouseover="showTip(event, '45', 147)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 148)" onmouseover="showTip(event, '46', 148)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 149)" onmouseover="showTip(event, '47', 149)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 150)" onmouseover="showTip(event, '48', 150)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span class="k">mutable</span> <span onmouseout="hideTip(event, '51', 151)" onmouseover="showTip(event, '51', 151)" class="mv">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 152)" onmouseover="showTip(event, '50', 152)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 153)" onmouseover="showTip(event, '52', 153)" class="id">initialState</span> <span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 154)" onmouseover="showTip(event, '53', 154)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 155)" onmouseover="showTip(event, '46', 155)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 156)" onmouseover="showTip(event, '54', 156)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 157)" onmouseover="showTip(event, '50', 157)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 158)" onmouseover="showTip(event, '55', 158)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 159)" onmouseover="showTip(event, '53', 159)" class="fn">command</span> <span onmouseout="hideTip(event, '51', 160)" onmouseover="showTip(event, '51', 160)" class="mv">state</span> <span onmouseout="hideTip(event, '51', 161)" onmouseover="showTip(event, '51', 161)" class="mv">state</span> <span class="k">&lt;-</span> <span onmouseout="hideTip(event, '41', 162)" onmouseover="showTip(event, '41', 162)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 163)" onmouseover="showTip(event, '42', 163)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 164)" onmouseover="showTip(event, '50', 164)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 165)" onmouseover="showTip(event, '56', 165)" class="id">evolve</span> <span onmouseout="hideTip(event, '51', 166)" onmouseover="showTip(event, '51', 166)" class="mv">state</span> <span onmouseout="hideTip(event, '54', 167)" onmouseover="showTip(event, '54', 167)" class="fn">events</span> <span onmouseout="hideTip(event, '54', 168)" onmouseover="showTip(event, '54', 168)" class="fn">events</span> </code></pre> <p>For any decider we can now call the start function. It will return a function which given a command, returns the list of Events and is ready to handle the next command.</p> <h2><a name="Run-on-a-database" class="anchor" href="#Run-on-a-database">Run on a database</a></h2> <p>The previous implementation is not persistent, and will lose any state once closed. We can persist state in a database like any classic application:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">WithPersistence</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '62', 179)" onmouseover="showTip(event, '62', 179)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 180)" onmouseover="showTip(event, '50', 180)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 181)" onmouseover="showTip(event, '45', 181)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 182)" onmouseover="showTip(event, '46', 182)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 183)" onmouseover="showTip(event, '47', 183)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 184)" onmouseover="showTip(event, '48', 184)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '58', 185)" onmouseover="showTip(event, '58', 185)" class="fn">id</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 186)" onmouseover="showTip(event, '53', 186)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 187)" onmouseover="showTip(event, '46', 187)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="c">// load state from database</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 188)" onmouseover="showTip(event, '60', 188)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '63', 189)" onmouseover="showTip(event, '63', 189)" class="m">Storage</span><span class="pn">.</span><span onmouseout="hideTip(event, '57', 190)" onmouseover="showTip(event, '57', 190)" class="id">loadState</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 191)" onmouseover="showTip(event, '58', 191)" class="fn">id</span><span class="pn">)</span> <span class="c">// this is the decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 192)" onmouseover="showTip(event, '54', 192)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 193)" onmouseover="showTip(event, '50', 193)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 194)" onmouseover="showTip(event, '55', 194)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 195)" onmouseover="showTip(event, '53', 195)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 196)" onmouseover="showTip(event, '60', 196)" class="fn">state</span> <span class="c">// compute new state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '64', 197)" onmouseover="showTip(event, '64', 197)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 198)" onmouseover="showTip(event, '41', 198)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 199)" onmouseover="showTip(event, '42', 199)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 200)" onmouseover="showTip(event, '50', 200)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 201)" onmouseover="showTip(event, '56', 201)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 202)" onmouseover="showTip(event, '60', 202)" class="fn">state</span> <span onmouseout="hideTip(event, '54', 203)" onmouseover="showTip(event, '54', 203)" class="fn">events</span> <span class="c">// save state in database</span> <span onmouseout="hideTip(event, '63', 204)" onmouseover="showTip(event, '63', 204)" class="m">Storage</span><span class="pn">.</span><span onmouseout="hideTip(event, '59', 205)" onmouseover="showTip(event, '59', 205)" class="id">saveState</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 206)" onmouseover="showTip(event, '58', 206)" class="fn">id</span><span class="pn">,</span> <span onmouseout="hideTip(event, '64', 207)" onmouseover="showTip(event, '64', 207)" class="fn">newState</span><span class="pn">)</span> <span onmouseout="hideTip(event, '54', 208)" onmouseover="showTip(event, '54', 208)" class="fn">events</span> </code></pre> <p>This version is simple, but can be dangerous if the state can be modified concurrently. If operations can never be concurrent, this code is simple and perfectly fine.</p> <p>It is then easily protected using an etag. This is usually a string returned by the database that is modified on each change. The database can check that the provided etag matches the actual etag before applying the update.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">PersistenceWithEtag</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '62', 224)" onmouseover="showTip(event, '62', 224)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 225)" onmouseover="showTip(event, '50', 225)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 226)" onmouseover="showTip(event, '45', 226)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 227)" onmouseover="showTip(event, '46', 227)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 228)" onmouseover="showTip(event, '47', 228)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 229)" onmouseover="showTip(event, '48', 229)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '58', 230)" onmouseover="showTip(event, '58', 230)" class="fn">id</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 231)" onmouseover="showTip(event, '53', 231)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 232)" onmouseover="showTip(event, '46', 232)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '69', 233)" onmouseover="showTip(event, '69', 233)" class="fn">handle</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// load state and etag</span> <span class="k">let</span> <span onmouseout="hideTip(event, '68', 234)" onmouseover="showTip(event, '68', 234)" class="fn">etag</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 235)" onmouseover="showTip(event, '60', 235)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '70', 236)" onmouseover="showTip(event, '70', 236)" class="m">StorageWithEtag</span><span class="pn">.</span><span onmouseout="hideTip(event, '66', 237)" onmouseover="showTip(event, '66', 237)" class="id">loadState</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 238)" onmouseover="showTip(event, '58', 238)" class="fn">id</span><span class="pn">)</span> <span class="c">// this is the decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 239)" onmouseover="showTip(event, '54', 239)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 240)" onmouseover="showTip(event, '50', 240)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 241)" onmouseover="showTip(event, '55', 241)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 242)" onmouseover="showTip(event, '53', 242)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 243)" onmouseover="showTip(event, '60', 243)" class="fn">state</span> <span class="c">// compute the new state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '64', 244)" onmouseover="showTip(event, '64', 244)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 245)" onmouseover="showTip(event, '41', 245)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 246)" onmouseover="showTip(event, '42', 246)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 247)" onmouseover="showTip(event, '50', 247)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 248)" onmouseover="showTip(event, '56', 248)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 249)" onmouseover="showTip(event, '60', 249)" class="fn">state</span> <span onmouseout="hideTip(event, '54', 250)" onmouseover="showTip(event, '54', 250)" class="fn">events</span> <span class="c">// try to save, checking the state still match etag</span> <span class="k">if</span> <span onmouseout="hideTip(event, '70', 251)" onmouseover="showTip(event, '70', 251)" class="m">StorageWithEtag</span><span class="pn">.</span><span onmouseout="hideTip(event, '67', 252)" onmouseover="showTip(event, '67', 252)" class="id">trySaveState</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 253)" onmouseover="showTip(event, '58', 253)" class="fn">id</span><span class="pn">,</span> <span onmouseout="hideTip(event, '68', 254)" onmouseover="showTip(event, '68', 254)" class="fn">etag</span><span class="pn">,</span> <span onmouseout="hideTip(event, '64', 255)" onmouseover="showTip(event, '64', 255)" class="fn">newState</span><span class="pn">)</span> <span class="k">then</span> <span onmouseout="hideTip(event, '54', 256)" onmouseover="showTip(event, '54', 256)" class="fn">events</span> <span class="k">else</span> <span onmouseout="hideTip(event, '69', 257)" onmouseover="showTip(event, '69', 257)" class="fn">handle</span><span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '69', 258)" onmouseover="showTip(event, '69', 258)" class="fn">handle</span><span class="pn">(</span><span class="pn">)</span> </code></pre> <p>This version will stubbornly retry until we avoid the concurrency problem.</p> <p>It is also possible to keep state in memory to avoid loading state on each call. However in case of conflict, we will reload the state as well as the current Etag</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">PersistenceWithEtagAndRetry</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '73', 273)" onmouseover="showTip(event, '73', 273)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 274)" onmouseover="showTip(event, '50', 274)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 275)" onmouseover="showTip(event, '45', 275)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 276)" onmouseover="showTip(event, '46', 276)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 277)" onmouseover="showTip(event, '47', 277)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 278)" onmouseover="showTip(event, '48', 278)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// load initial state</span> <span class="k">let</span> <span class="k">mutable</span> <span onmouseout="hideTip(event, '74', 279)" onmouseover="showTip(event, '74', 279)" class="mv">etagAndState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '75', 280)" onmouseover="showTip(event, '75', 280)" class="m">StorageWithEtagAndRetry</span><span class="pn">.</span><span onmouseout="hideTip(event, '66', 281)" onmouseover="showTip(event, '66', 281)" class="id">loadState</span><span class="pn">(</span><span onmouseout="hideTip(event, '76', 282)" onmouseover="showTip(event, '76', 282)" class="fn">id</span><span class="pn">)</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '58', 283)" onmouseover="showTip(event, '58', 283)" class="fn">id</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 284)" onmouseover="showTip(event, '53', 284)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 285)" onmouseover="showTip(event, '46', 285)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '77', 286)" onmouseover="showTip(event, '77', 286)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '68', 287)" onmouseover="showTip(event, '68', 287)" class="fn">etag</span><span class="pn">,</span> <span onmouseout="hideTip(event, '78', 288)" onmouseover="showTip(event, '78', 288)" class="fn">state</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span class="pn">(</span><span onmouseout="hideTip(event, '68', 289)" onmouseover="showTip(event, '68', 289)" class="fn">etag</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 290)" onmouseover="showTip(event, '60', 290)" class="fn">state</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '74', 291)" onmouseover="showTip(event, '74', 291)" class="mv">etagAndState</span> <span class="c">// this is the decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 292)" onmouseover="showTip(event, '54', 292)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 293)" onmouseover="showTip(event, '50', 293)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 294)" onmouseover="showTip(event, '55', 294)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 295)" onmouseover="showTip(event, '53', 295)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 296)" onmouseover="showTip(event, '60', 296)" class="fn">state</span> <span class="c">// compute new state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '64', 297)" onmouseover="showTip(event, '64', 297)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 298)" onmouseover="showTip(event, '41', 298)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 299)" onmouseover="showTip(event, '42', 299)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 300)" onmouseover="showTip(event, '50', 300)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 301)" onmouseover="showTip(event, '56', 301)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 302)" onmouseover="showTip(event, '60', 302)" class="fn">state</span> <span onmouseout="hideTip(event, '54', 303)" onmouseover="showTip(event, '54', 303)" class="fn">events</span> <span class="c">// try to save, checking the state still matches the etag</span> <span class="k">match</span> <span onmouseout="hideTip(event, '75', 304)" onmouseover="showTip(event, '75', 304)" class="m">StorageWithEtagAndRetry</span><span class="pn">.</span><span onmouseout="hideTip(event, '71', 305)" onmouseover="showTip(event, '71', 305)" class="id">trySaveState</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 306)" onmouseover="showTip(event, '58', 306)" class="fn">id</span><span class="pn">,</span> <span onmouseout="hideTip(event, '68', 307)" onmouseover="showTip(event, '68', 307)" class="fn">etag</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 308)" onmouseover="showTip(event, '60', 308)" class="fn">state</span><span class="pn">)</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '79', 309)" onmouseover="showTip(event, '79', 309)" class="uc">Some</span> <span onmouseout="hideTip(event, '80', 310)" onmouseover="showTip(event, '80', 310)" class="fn">newEtag</span> <span class="k">-&gt;</span> <span class="c">// state has been saved</span> <span onmouseout="hideTip(event, '74', 311)" onmouseover="showTip(event, '74', 311)" class="mv">etagAndState</span> <span class="k">&lt;-</span> <span class="pn">(</span><span onmouseout="hideTip(event, '80', 312)" onmouseover="showTip(event, '80', 312)" class="fn">newEtag</span><span class="pn">,</span> <span onmouseout="hideTip(event, '64', 313)" onmouseover="showTip(event, '64', 313)" class="fn">newState</span><span class="pn">)</span> <span onmouseout="hideTip(event, '54', 314)" onmouseover="showTip(event, '54', 314)" class="fn">events</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '81', 315)" onmouseover="showTip(event, '81', 315)" class="uc">None</span> <span class="k">-&gt;</span> <span class="c">// a conflict occurred, reload etag and state</span> <span class="c">// from database and retry</span> <span onmouseout="hideTip(event, '77', 316)" onmouseover="showTip(event, '77', 316)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '75', 317)" onmouseover="showTip(event, '75', 317)" class="m">StorageWithEtagAndRetry</span><span class="pn">.</span><span onmouseout="hideTip(event, '66', 318)" onmouseover="showTip(event, '66', 318)" class="id">loadState</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 319)" onmouseover="showTip(event, '58', 319)" class="fn">id</span><span class="pn">)</span><span class="pn">)</span> <span onmouseout="hideTip(event, '77', 320)" onmouseover="showTip(event, '77', 320)" class="fn">handle</span> <span onmouseout="hideTip(event, '74', 321)" onmouseover="showTip(event, '74', 321)" class="mv">etagAndState</span> </code></pre> <p>It is possible to also store events in an Event Store, but still load/save state on each call. In this case, events can be used to recompute the current State when a refactoring alters its shape. Instead of migrating the old state version to new version using a one time script, you can fold all saved events through the evolve function and save state with this new version. This is actually the equivalent of saving a <a href="#Snapshots">snapshot</a> on each call.</p> <h2><a name="Run-on-an-event-store" class="anchor" href="#Run-on-an-event-store">Run on an event store</a></h2> <p>It can also easily be implemented using an event store</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">WithEventStore</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '88', 337)" onmouseover="showTip(event, '88', 337)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 338)" onmouseover="showTip(event, '50', 338)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 339)" onmouseover="showTip(event, '45', 339)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 340)" onmouseover="showTip(event, '46', 340)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 341)" onmouseover="showTip(event, '47', 341)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 342)" onmouseover="showTip(event, '48', 342)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '85', 343)" onmouseover="showTip(event, '85', 343)" class="fn">stream</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 344)" onmouseover="showTip(event, '53', 344)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 345)" onmouseover="showTip(event, '46', 345)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="c">// load all past events to compute current state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 346)" onmouseover="showTip(event, '60', 346)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '89', 347)" onmouseover="showTip(event, '89', 347)" class="m">EventStore</span><span class="pn">.</span><span onmouseout="hideTip(event, '84', 348)" onmouseover="showTip(event, '84', 348)" class="id">loadEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 349)" onmouseover="showTip(event, '85', 349)" class="fn">stream</span><span class="pn">,</span> <span class="n">0</span><span class="pn">)</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '41', 350)" onmouseover="showTip(event, '41', 350)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 351)" onmouseover="showTip(event, '42', 351)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 352)" onmouseover="showTip(event, '50', 352)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 353)" onmouseover="showTip(event, '56', 353)" class="id">evolve</span> <span onmouseout="hideTip(event, '50', 354)" onmouseover="showTip(event, '50', 354)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 355)" onmouseover="showTip(event, '52', 355)" class="id">initialState</span> <span class="c">// get events from the decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 356)" onmouseover="showTip(event, '54', 356)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 357)" onmouseover="showTip(event, '50', 357)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 358)" onmouseover="showTip(event, '55', 358)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 359)" onmouseover="showTip(event, '53', 359)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 360)" onmouseover="showTip(event, '60', 360)" class="fn">state</span> <span class="c">// append events to stream</span> <span onmouseout="hideTip(event, '89', 361)" onmouseover="showTip(event, '89', 361)" class="m">EventStore</span><span class="pn">.</span><span onmouseout="hideTip(event, '87', 362)" onmouseover="showTip(event, '87', 362)" class="id">appendEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 363)" onmouseover="showTip(event, '85', 363)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 364)" onmouseover="showTip(event, '54', 364)" class="fn">events</span><span class="pn">)</span> <span onmouseout="hideTip(event, '54', 365)" onmouseover="showTip(event, '54', 365)" class="fn">events</span> </code></pre> <p>This version is reloading all the events from the beginning on each command. This is perfectly reasonable for short streams. Since events are usually small in size, loading less that 100 events is very fast and folding them, almost instant (think of it as a loop of 100 iterations that does a few basic operations).</p> <p>As with the database-backed version, we can protect it against concurrent appends to the stream. Here we use stream version which is usually provided by the Event Store. The appendEvents function now takes an expected version and will reject append if the stream version is not matching. If it is not matching it will return the new version as well as events that have been appended since the one anticipated.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">WithEventStoreAndVersion</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '88', 385)" onmouseover="showTip(event, '88', 385)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 386)" onmouseover="showTip(event, '50', 386)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 387)" onmouseover="showTip(event, '45', 387)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 388)" onmouseover="showTip(event, '46', 388)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 389)" onmouseover="showTip(event, '47', 389)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 390)" onmouseover="showTip(event, '48', 390)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '85', 391)" onmouseover="showTip(event, '85', 391)" class="fn">stream</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 392)" onmouseover="showTip(event, '53', 392)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 393)" onmouseover="showTip(event, '46', 393)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '94', 394)" onmouseover="showTip(event, '94', 394)" class="fn">handle</span> <span onmouseout="hideTip(event, '86', 395)" onmouseover="showTip(event, '86', 395)" class="fn">version</span> <span onmouseout="hideTip(event, '60', 396)" onmouseover="showTip(event, '60', 396)" class="fn">state</span> <span class="o">=</span> <span class="c">// get events from decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 397)" onmouseover="showTip(event, '54', 397)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 398)" onmouseover="showTip(event, '50', 398)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 399)" onmouseover="showTip(event, '55', 399)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 400)" onmouseover="showTip(event, '53', 400)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 401)" onmouseover="showTip(event, '60', 401)" class="fn">state</span> <span class="k">match</span> <span onmouseout="hideTip(event, '95', 402)" onmouseover="showTip(event, '95', 402)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 403)" onmouseover="showTip(event, '91', 403)" class="id">tryAppendEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 404)" onmouseover="showTip(event, '85', 404)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '86', 405)" onmouseover="showTip(event, '86', 405)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 406)" onmouseover="showTip(event, '54', 406)" class="fn">events</span><span class="pn">)</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '96', 407)" onmouseover="showTip(event, '96', 407)" class="uc">Ok</span> <span onmouseout="hideTip(event, '86', 408)" onmouseover="showTip(event, '86', 408)" class="fn">version</span> <span class="k">-&gt;</span> <span class="c">// save succeeded, we can return events</span> <span onmouseout="hideTip(event, '54', 409)" onmouseover="showTip(event, '54', 409)" class="fn">events</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '97', 410)" onmouseover="showTip(event, '97', 410)" class="uc">Error</span> <span class="pn">(</span><span onmouseout="hideTip(event, '98', 411)" onmouseover="showTip(event, '98', 411)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '99', 412)" onmouseover="showTip(event, '99', 412)" class="fn">catchupEvents</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="c">// it failed, but we now have the events that we missed</span> <span class="c">// catch up the current state to the actual state in the database</span> <span class="k">let</span> <span onmouseout="hideTip(event, '100', 413)" onmouseover="showTip(event, '100', 413)" class="fn">actualState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 414)" onmouseover="showTip(event, '41', 414)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 415)" onmouseover="showTip(event, '42', 415)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 416)" onmouseover="showTip(event, '50', 416)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 417)" onmouseover="showTip(event, '56', 417)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 418)" onmouseover="showTip(event, '60', 418)" class="fn">state</span> <span onmouseout="hideTip(event, '99', 419)" onmouseover="showTip(event, '99', 419)" class="fn">catchupEvents</span> <span class="c">// and try again</span> <span onmouseout="hideTip(event, '94', 420)" onmouseover="showTip(event, '94', 420)" class="fn">handle</span> <span onmouseout="hideTip(event, '98', 421)" onmouseover="showTip(event, '98', 421)" class="fn">actualVersion</span> <span onmouseout="hideTip(event, '100', 422)" onmouseover="showTip(event, '100', 422)" class="fn">actualState</span> <span class="c">// load past events</span> <span class="k">let</span> <span onmouseout="hideTip(event, '86', 423)" onmouseover="showTip(event, '86', 423)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '101', 424)" onmouseover="showTip(event, '101', 424)" class="fn">pastEvents</span> <span class="o">=</span> <span onmouseout="hideTip(event, '95', 425)" onmouseover="showTip(event, '95', 425)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '90', 426)" onmouseover="showTip(event, '90', 426)" class="id">loadEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 427)" onmouseover="showTip(event, '85', 427)" class="fn">stream</span><span class="pn">)</span> <span class="c">// compute current state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 428)" onmouseover="showTip(event, '60', 428)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 429)" onmouseover="showTip(event, '41', 429)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 430)" onmouseover="showTip(event, '42', 430)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 431)" onmouseover="showTip(event, '50', 431)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 432)" onmouseover="showTip(event, '56', 432)" class="id">evolve</span> <span onmouseout="hideTip(event, '50', 433)" onmouseover="showTip(event, '50', 433)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 434)" onmouseover="showTip(event, '52', 434)" class="id">initialState</span> <span onmouseout="hideTip(event, '101', 435)" onmouseover="showTip(event, '101', 435)" class="fn">pastEvents</span> <span onmouseout="hideTip(event, '94', 436)" onmouseover="showTip(event, '94', 436)" class="fn">handle</span> <span onmouseout="hideTip(event, '86', 437)" onmouseover="showTip(event, '86', 437)" class="fn">version</span> <span onmouseout="hideTip(event, '60', 438)" onmouseover="showTip(event, '60', 438)" class="fn">state</span> </code></pre> <p>This can obviously be extended to keep state in memory:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">WithEventStoreInMemory</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '102', 439)" onmouseover="showTip(event, '102', 439)" class="fn">start</span> <span onmouseout="hideTip(event, '85', 440)" onmouseover="showTip(event, '85', 440)" class="fn">stream</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 441)" onmouseover="showTip(event, '50', 441)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 442)" onmouseover="showTip(event, '45', 442)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 443)" onmouseover="showTip(event, '46', 443)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 444)" onmouseover="showTip(event, '47', 444)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 445)" onmouseover="showTip(event, '48', 445)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span class="k">mutable</span> <span onmouseout="hideTip(event, '103', 446)" onmouseover="showTip(event, '103', 446)" class="mv">versionAndState</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '86', 447)" onmouseover="showTip(event, '86', 447)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '101', 448)" onmouseover="showTip(event, '101', 448)" class="fn">pastEvents</span> <span class="o">=</span> <span onmouseout="hideTip(event, '95', 449)" onmouseover="showTip(event, '95', 449)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '90', 450)" onmouseover="showTip(event, '90', 450)" class="id">loadEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 451)" onmouseover="showTip(event, '85', 451)" class="fn">stream</span><span class="pn">)</span> <span class="c">// compute current state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 452)" onmouseover="showTip(event, '60', 452)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 453)" onmouseover="showTip(event, '41', 453)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 454)" onmouseover="showTip(event, '42', 454)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 455)" onmouseover="showTip(event, '50', 455)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 456)" onmouseover="showTip(event, '56', 456)" class="id">evolve</span> <span onmouseout="hideTip(event, '50', 457)" onmouseover="showTip(event, '50', 457)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 458)" onmouseover="showTip(event, '52', 458)" class="id">initialState</span> <span onmouseout="hideTip(event, '101', 459)" onmouseover="showTip(event, '101', 459)" class="fn">pastEvents</span> <span onmouseout="hideTip(event, '86', 460)" onmouseover="showTip(event, '86', 460)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 461)" onmouseover="showTip(event, '60', 461)" class="fn">state</span> <span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 462)" onmouseover="showTip(event, '53', 462)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 463)" onmouseover="showTip(event, '46', 463)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '104', 464)" onmouseover="showTip(event, '104', 464)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '86', 465)" onmouseover="showTip(event, '86', 465)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 466)" onmouseover="showTip(event, '60', 466)" class="fn">state</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// get events from decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 467)" onmouseover="showTip(event, '54', 467)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 468)" onmouseover="showTip(event, '50', 468)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 469)" onmouseover="showTip(event, '55', 469)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 470)" onmouseover="showTip(event, '53', 470)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 471)" onmouseover="showTip(event, '60', 471)" class="fn">state</span> <span class="k">match</span> <span onmouseout="hideTip(event, '95', 472)" onmouseover="showTip(event, '95', 472)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 473)" onmouseover="showTip(event, '91', 473)" class="id">tryAppendEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 474)" onmouseover="showTip(event, '85', 474)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '86', 475)" onmouseover="showTip(event, '86', 475)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 476)" onmouseover="showTip(event, '54', 476)" class="fn">events</span><span class="pn">)</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '96', 477)" onmouseover="showTip(event, '96', 477)" class="uc">Ok</span> <span onmouseout="hideTip(event, '105', 478)" onmouseover="showTip(event, '105', 478)" class="fn">newVersion</span> <span class="k">-&gt;</span> <span class="c">// save succeeded, we can return events</span> <span class="k">let</span> <span onmouseout="hideTip(event, '64', 479)" onmouseover="showTip(event, '64', 479)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 480)" onmouseover="showTip(event, '41', 480)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 481)" onmouseover="showTip(event, '42', 481)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 482)" onmouseover="showTip(event, '50', 482)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 483)" onmouseover="showTip(event, '56', 483)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 484)" onmouseover="showTip(event, '60', 484)" class="fn">state</span> <span onmouseout="hideTip(event, '54', 485)" onmouseover="showTip(event, '54', 485)" class="fn">events</span> <span onmouseout="hideTip(event, '103', 486)" onmouseover="showTip(event, '103', 486)" class="mv">versionAndState</span> <span class="k">&lt;-</span> <span class="pn">(</span><span onmouseout="hideTip(event, '105', 487)" onmouseover="showTip(event, '105', 487)" class="fn">newVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '64', 488)" onmouseover="showTip(event, '64', 488)" class="fn">newState</span><span class="pn">)</span> <span onmouseout="hideTip(event, '54', 489)" onmouseover="showTip(event, '54', 489)" class="fn">events</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '97', 490)" onmouseover="showTip(event, '97', 490)" class="uc">Error</span> <span class="pn">(</span><span onmouseout="hideTip(event, '98', 491)" onmouseover="showTip(event, '98', 491)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '99', 492)" onmouseover="showTip(event, '99', 492)" class="fn">catchupEvents</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="c">// it failed, but we have events that we missed</span> <span class="c">// compute current state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '100', 493)" onmouseover="showTip(event, '100', 493)" class="fn">actualState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 494)" onmouseover="showTip(event, '41', 494)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 495)" onmouseover="showTip(event, '42', 495)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 496)" onmouseover="showTip(event, '50', 496)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 497)" onmouseover="showTip(event, '56', 497)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 498)" onmouseover="showTip(event, '60', 498)" class="fn">state</span> <span onmouseout="hideTip(event, '99', 499)" onmouseover="showTip(event, '99', 499)" class="fn">catchupEvents</span> <span class="c">// and try again</span> <span onmouseout="hideTip(event, '104', 500)" onmouseover="showTip(event, '104', 500)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '98', 501)" onmouseover="showTip(event, '98', 501)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '100', 502)" onmouseover="showTip(event, '100', 502)" class="fn">actualState</span><span class="pn">)</span> <span onmouseout="hideTip(event, '104', 503)" onmouseover="showTip(event, '104', 503)" class="fn">handle</span> <span onmouseout="hideTip(event, '103', 504)" onmouseover="showTip(event, '103', 504)" class="mv">versionAndState</span> </code></pre> <h2><a name="Snapshots" class="anchor" href="#Snapshots">Snapshots</a></h2> <p>Once you have many events, it can start taking a long time to reload everything. It is then possible to save the state periodically along with the version of the stream that produced this state. The snapshots can be saved in a key value store:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">WithSnapshots</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '73', 523)" onmouseover="showTip(event, '73', 523)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 524)" onmouseover="showTip(event, '50', 524)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 525)" onmouseover="showTip(event, '45', 525)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 526)" onmouseover="showTip(event, '46', 526)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 527)" onmouseover="showTip(event, '47', 527)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 528)" onmouseover="showTip(event, '48', 528)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// load state using snapshot if any</span> <span class="k">let</span> <span onmouseout="hideTip(event, '110', 529)" onmouseover="showTip(event, '110', 529)" class="fn">loadState</span> <span onmouseout="hideTip(event, '111', 530)" onmouseover="showTip(event, '111', 530)" class="fn">stream</span> <span class="o">=</span> <span class="c">// load snapshot</span> <span class="k">let</span> <span onmouseout="hideTip(event, '112', 531)" onmouseover="showTip(event, '112', 531)" class="fn">snapVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '113', 532)" onmouseover="showTip(event, '113', 532)" class="fn">snapState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '114', 533)" onmouseover="showTip(event, '114', 533)" class="m">Snapshots</span><span class="pn">.</span><span onmouseout="hideTip(event, '106', 534)" onmouseover="showTip(event, '106', 534)" class="id">tryLoadSnapshot</span><span class="pn">(</span><span onmouseout="hideTip(event, '111', 535)" onmouseover="showTip(event, '111', 535)" class="fn">stream</span><span class="pn">)</span> <span class="c">// fallback to version 0 and initialState if not found</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '115', 536)" onmouseover="showTip(event, '115', 536)" class="m">Option</span><span class="pn">.</span><span onmouseout="hideTip(event, '116', 537)" onmouseover="showTip(event, '116', 537)" class="id">defaultValue</span> <span class="pn">(</span><span class="n">0</span><span class="pn">,</span> <span onmouseout="hideTip(event, '50', 538)" onmouseover="showTip(event, '50', 538)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 539)" onmouseover="showTip(event, '52', 539)" class="id">initialState</span><span class="pn">)</span> <span class="c">// load version and events after snapshot</span> <span class="k">let</span> <span onmouseout="hideTip(event, '86', 540)" onmouseover="showTip(event, '86', 540)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 541)" onmouseover="showTip(event, '54', 541)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '95', 542)" onmouseover="showTip(event, '95', 542)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '90', 543)" onmouseover="showTip(event, '90', 543)" class="id">loadEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '111', 544)" onmouseover="showTip(event, '111', 544)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '112', 545)" onmouseover="showTip(event, '112', 545)" class="fn">snapVersion</span><span class="pn">)</span> <span class="c">// fold events after snapshot</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 546)" onmouseover="showTip(event, '60', 546)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 547)" onmouseover="showTip(event, '41', 547)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 548)" onmouseover="showTip(event, '42', 548)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 549)" onmouseover="showTip(event, '50', 549)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 550)" onmouseover="showTip(event, '56', 550)" class="id">evolve</span> <span onmouseout="hideTip(event, '113', 551)" onmouseover="showTip(event, '113', 551)" class="fn">snapState</span> <span onmouseout="hideTip(event, '54', 552)" onmouseover="showTip(event, '54', 552)" class="fn">events</span> <span onmouseout="hideTip(event, '86', 553)" onmouseover="showTip(event, '86', 553)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 554)" onmouseover="showTip(event, '60', 554)" class="fn">state</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '85', 555)" onmouseover="showTip(event, '85', 555)" class="fn">stream</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 556)" onmouseover="showTip(event, '53', 556)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 557)" onmouseover="showTip(event, '46', 557)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '104', 558)" onmouseover="showTip(event, '104', 558)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '86', 559)" onmouseover="showTip(event, '86', 559)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 560)" onmouseover="showTip(event, '60', 560)" class="fn">state</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// get events from the decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 561)" onmouseover="showTip(event, '54', 561)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 562)" onmouseover="showTip(event, '50', 562)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 563)" onmouseover="showTip(event, '55', 563)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 564)" onmouseover="showTip(event, '53', 564)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 565)" onmouseover="showTip(event, '60', 565)" class="fn">state</span> <span class="c">// append events to stream</span> <span class="k">match</span> <span onmouseout="hideTip(event, '95', 566)" onmouseover="showTip(event, '95', 566)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 567)" onmouseover="showTip(event, '91', 567)" class="id">tryAppendEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 568)" onmouseover="showTip(event, '85', 568)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '86', 569)" onmouseover="showTip(event, '86', 569)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 570)" onmouseover="showTip(event, '54', 570)" class="fn">events</span><span class="pn">)</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '96', 571)" onmouseover="showTip(event, '96', 571)" class="uc">Ok</span> <span onmouseout="hideTip(event, '105', 572)" onmouseover="showTip(event, '105', 572)" class="fn">newVersion</span> <span class="k">-&gt;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '108', 573)" onmouseover="showTip(event, '108', 573)" class="fn">isTimeToSnapshot</span> <span onmouseout="hideTip(event, '86', 574)" onmouseover="showTip(event, '86', 574)" class="fn">version</span> <span class="k">then</span> <span class="c">// it is time to save snapshot</span> <span class="c">// compute state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '64', 575)" onmouseover="showTip(event, '64', 575)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 576)" onmouseover="showTip(event, '41', 576)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 577)" onmouseover="showTip(event, '42', 577)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 578)" onmouseover="showTip(event, '50', 578)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 579)" onmouseover="showTip(event, '56', 579)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 580)" onmouseover="showTip(event, '60', 580)" class="fn">state</span> <span onmouseout="hideTip(event, '54', 581)" onmouseover="showTip(event, '54', 581)" class="fn">events</span> <span class="c">// save it</span> <span onmouseout="hideTip(event, '114', 582)" onmouseover="showTip(event, '114', 582)" class="m">Snapshots</span><span class="pn">.</span><span onmouseout="hideTip(event, '107', 583)" onmouseover="showTip(event, '107', 583)" class="id">saveSnapshot</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 584)" onmouseover="showTip(event, '85', 584)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '105', 585)" onmouseover="showTip(event, '105', 585)" class="fn">newVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '64', 586)" onmouseover="showTip(event, '64', 586)" class="fn">newState</span><span class="pn">)</span> <span onmouseout="hideTip(event, '54', 587)" onmouseover="showTip(event, '54', 587)" class="fn">events</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '97', 588)" onmouseover="showTip(event, '97', 588)" class="uc">Error</span><span class="pn">(</span><span onmouseout="hideTip(event, '98', 589)" onmouseover="showTip(event, '98', 589)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '99', 590)" onmouseover="showTip(event, '99', 590)" class="fn">catchupEvents</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="c">// there was a concurrent write</span> <span class="c">// catch-up missing events and retry</span> <span class="k">let</span> <span onmouseout="hideTip(event, '100', 591)" onmouseover="showTip(event, '100', 591)" class="fn">actualState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 592)" onmouseover="showTip(event, '41', 592)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 593)" onmouseover="showTip(event, '42', 593)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 594)" onmouseover="showTip(event, '50', 594)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 595)" onmouseover="showTip(event, '56', 595)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 596)" onmouseover="showTip(event, '60', 596)" class="fn">state</span> <span onmouseout="hideTip(event, '99', 597)" onmouseover="showTip(event, '99', 597)" class="fn">catchupEvents</span> <span onmouseout="hideTip(event, '104', 598)" onmouseover="showTip(event, '104', 598)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '98', 599)" onmouseover="showTip(event, '98', 599)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '100', 600)" onmouseover="showTip(event, '100', 600)" class="fn">actualState</span><span class="pn">)</span> <span class="c">// load all past events to compute current state</span> <span class="c">// using snapshot if any</span> <span class="k">let</span> <span onmouseout="hideTip(event, '86', 601)" onmouseover="showTip(event, '86', 601)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 602)" onmouseover="showTip(event, '60', 602)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '110', 603)" onmouseover="showTip(event, '110', 603)" class="fn">loadState</span> <span onmouseout="hideTip(event, '85', 604)" onmouseover="showTip(event, '85', 604)" class="fn">stream</span> <span onmouseout="hideTip(event, '104', 605)" onmouseover="showTip(event, '104', 605)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '86', 606)" onmouseover="showTip(event, '86', 606)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 607)" onmouseover="showTip(event, '60', 607)" class="fn">state</span><span class="pn">)</span> </code></pre> <p>Here again we have the problem of snapshot invalidation. The easiest way to deal with it is to store all snapshots for a same version of the code in a same collection, container or database, and change it when snapshots are not valid anymore. This happens when the structure of the state changes after a refactoring. The saved snapshots won't have the expected shape which could cause some errors.</p> <p>You can just change the collection/container/database name when this happen. The collection will be empty on start and snapshots will be recomputed. You may even opt to recompute snapshots in advance before deploying a new version.</p> <p>Once we've deployed and verified that old version is not needed anymore, you can just delete the old collection.</p> <p>Conceptually, you would compute the collection name as a hash of the evolve function. This way, snapshots will be automatically invalidated when the evolve function changes (which always happens when the state structure changes)</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span onmouseout="hideTip(event, '121', 626)" onmouseover="showTip(event, '121', 626)" class="m">WithSnapshotsInContainers</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '73', 627)" onmouseover="showTip(event, '73', 627)" class="fn">start</span> <span class="pn">(</span><span onmouseout="hideTip(event, '50', 628)" onmouseover="showTip(event, '50', 628)" class="fn">decider</span><span class="pn">:</span> <span onmouseout="hideTip(event, '45', 629)" onmouseover="showTip(event, '45', 629)" class="rt">Decider</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 630)" onmouseover="showTip(event, '46', 630)" class="id">c</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '47', 631)" onmouseover="showTip(event, '47', 631)" class="id">e</span><span class="pn">,</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '48', 632)" onmouseover="showTip(event, '48', 632)" class="id">s</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '122', 633)" onmouseover="showTip(event, '122', 633)" class="fn">container</span> <span class="o">=</span> <span onmouseout="hideTip(event, '120', 634)" onmouseover="showTip(event, '120', 634)" class="fn">getContainerFromDecideHash</span><span class="pn">(</span><span onmouseout="hideTip(event, '50', 635)" onmouseover="showTip(event, '50', 635)" class="fn">decider</span><span class="pn">)</span> <span class="c">// load state using snapshot if any</span> <span class="k">let</span> <span onmouseout="hideTip(event, '110', 636)" onmouseover="showTip(event, '110', 636)" class="fn">loadState</span> <span onmouseout="hideTip(event, '111', 637)" onmouseover="showTip(event, '111', 637)" class="fn">stream</span> <span class="o">=</span> <span class="c">// load snapshot.. it will not be found if container has</span> <span class="c">// changed since last run</span> <span class="k">let</span> <span onmouseout="hideTip(event, '112', 638)" onmouseover="showTip(event, '112', 638)" class="fn">snapVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '113', 639)" onmouseover="showTip(event, '113', 639)" class="fn">snapState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '123', 640)" onmouseover="showTip(event, '123', 640)" class="m">SnapshotsWithContainer</span><span class="pn">.</span><span onmouseout="hideTip(event, '117', 641)" onmouseover="showTip(event, '117', 641)" class="id">tryLoadSnapshot</span><span class="pn">(</span><span onmouseout="hideTip(event, '111', 642)" onmouseover="showTip(event, '111', 642)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '122', 643)" onmouseover="showTip(event, '122', 643)" class="fn">container</span><span class="pn">)</span> <span class="c">// fallback to version 0 and initialState if not found</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '115', 644)" onmouseover="showTip(event, '115', 644)" class="m">Option</span><span class="pn">.</span><span onmouseout="hideTip(event, '116', 645)" onmouseover="showTip(event, '116', 645)" class="id">defaultValue</span> <span class="pn">(</span><span class="n">0</span><span class="pn">,</span> <span onmouseout="hideTip(event, '50', 646)" onmouseover="showTip(event, '50', 646)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 647)" onmouseover="showTip(event, '52', 647)" class="id">initialState</span><span class="pn">)</span> <span class="c">// load version and events after snapshot</span> <span class="k">let</span> <span onmouseout="hideTip(event, '86', 648)" onmouseover="showTip(event, '86', 648)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 649)" onmouseover="showTip(event, '54', 649)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '95', 650)" onmouseover="showTip(event, '95', 650)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '90', 651)" onmouseover="showTip(event, '90', 651)" class="id">loadEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '111', 652)" onmouseover="showTip(event, '111', 652)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '112', 653)" onmouseover="showTip(event, '112', 653)" class="fn">snapVersion</span><span class="pn">)</span> <span class="c">// fold events after snapshot</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 654)" onmouseover="showTip(event, '60', 654)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 655)" onmouseover="showTip(event, '41', 655)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 656)" onmouseover="showTip(event, '42', 656)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 657)" onmouseover="showTip(event, '50', 657)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 658)" onmouseover="showTip(event, '56', 658)" class="id">evolve</span> <span onmouseout="hideTip(event, '113', 659)" onmouseover="showTip(event, '113', 659)" class="fn">snapState</span> <span onmouseout="hideTip(event, '54', 660)" onmouseover="showTip(event, '54', 660)" class="fn">events</span> <span onmouseout="hideTip(event, '86', 661)" onmouseover="showTip(event, '86', 661)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 662)" onmouseover="showTip(event, '60', 662)" class="fn">state</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '85', 663)" onmouseover="showTip(event, '85', 663)" class="fn">stream</span> <span class="pn">(</span><span onmouseout="hideTip(event, '53', 664)" onmouseover="showTip(event, '53', 664)" class="fn">command</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '46', 665)" onmouseover="showTip(event, '46', 665)" class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '104', 666)" onmouseover="showTip(event, '104', 666)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '86', 667)" onmouseover="showTip(event, '86', 667)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 668)" onmouseover="showTip(event, '60', 668)" class="fn">state</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// get events from the decision</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 669)" onmouseover="showTip(event, '54', 669)" class="fn">events</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 670)" onmouseover="showTip(event, '50', 670)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '55', 671)" onmouseover="showTip(event, '55', 671)" class="id">decide</span> <span onmouseout="hideTip(event, '53', 672)" onmouseover="showTip(event, '53', 672)" class="fn">command</span> <span onmouseout="hideTip(event, '60', 673)" onmouseover="showTip(event, '60', 673)" class="fn">state</span> <span class="c">// append events to stream</span> <span class="k">match</span> <span onmouseout="hideTip(event, '95', 674)" onmouseover="showTip(event, '95', 674)" class="m">EventStoreWithVersion</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 675)" onmouseover="showTip(event, '91', 675)" class="id">tryAppendEvents</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 676)" onmouseover="showTip(event, '85', 676)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '86', 677)" onmouseover="showTip(event, '86', 677)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '54', 678)" onmouseover="showTip(event, '54', 678)" class="fn">events</span><span class="pn">)</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '96', 679)" onmouseover="showTip(event, '96', 679)" class="uc">Ok</span> <span onmouseout="hideTip(event, '105', 680)" onmouseover="showTip(event, '105', 680)" class="fn">newVersion</span> <span class="k">-&gt;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '108', 681)" onmouseover="showTip(event, '108', 681)" class="fn">isTimeToSnapshot</span> <span onmouseout="hideTip(event, '86', 682)" onmouseover="showTip(event, '86', 682)" class="fn">version</span> <span class="k">then</span> <span class="c">// it is time to save snapshot</span> <span class="c">// compute state</span> <span class="k">let</span> <span onmouseout="hideTip(event, '64', 683)" onmouseover="showTip(event, '64', 683)" class="fn">newState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 684)" onmouseover="showTip(event, '41', 684)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 685)" onmouseover="showTip(event, '42', 685)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 686)" onmouseover="showTip(event, '50', 686)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 687)" onmouseover="showTip(event, '56', 687)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 688)" onmouseover="showTip(event, '60', 688)" class="fn">state</span> <span onmouseout="hideTip(event, '54', 689)" onmouseover="showTip(event, '54', 689)" class="fn">events</span> <span class="c">// save it</span> <span onmouseout="hideTip(event, '123', 690)" onmouseover="showTip(event, '123', 690)" class="m">SnapshotsWithContainer</span><span class="pn">.</span><span onmouseout="hideTip(event, '119', 691)" onmouseover="showTip(event, '119', 691)" class="id">saveSnapshot</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 692)" onmouseover="showTip(event, '85', 692)" class="fn">stream</span><span class="pn">,</span> <span onmouseout="hideTip(event, '122', 693)" onmouseover="showTip(event, '122', 693)" class="fn">container</span><span class="pn">,</span> <span onmouseout="hideTip(event, '105', 694)" onmouseover="showTip(event, '105', 694)" class="fn">newVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '64', 695)" onmouseover="showTip(event, '64', 695)" class="fn">newState</span><span class="pn">)</span> <span onmouseout="hideTip(event, '54', 696)" onmouseover="showTip(event, '54', 696)" class="fn">events</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '97', 697)" onmouseover="showTip(event, '97', 697)" class="uc">Error</span><span class="pn">(</span><span onmouseout="hideTip(event, '98', 698)" onmouseover="showTip(event, '98', 698)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '99', 699)" onmouseover="showTip(event, '99', 699)" class="fn">catchupEvents</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="c">// there was a concurrent write</span> <span class="c">// catch-up missing events and retry</span> <span class="k">let</span> <span onmouseout="hideTip(event, '100', 700)" onmouseover="showTip(event, '100', 700)" class="fn">actualState</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 701)" onmouseover="showTip(event, '41', 701)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 702)" onmouseover="showTip(event, '42', 702)" class="id">fold</span> <span onmouseout="hideTip(event, '50', 703)" onmouseover="showTip(event, '50', 703)" class="fn">decider</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 704)" onmouseover="showTip(event, '56', 704)" class="id">evolve</span> <span onmouseout="hideTip(event, '60', 705)" onmouseover="showTip(event, '60', 705)" class="fn">state</span> <span onmouseout="hideTip(event, '99', 706)" onmouseover="showTip(event, '99', 706)" class="fn">catchupEvents</span> <span onmouseout="hideTip(event, '104', 707)" onmouseover="showTip(event, '104', 707)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '98', 708)" onmouseover="showTip(event, '98', 708)" class="fn">actualVersion</span><span class="pn">,</span> <span onmouseout="hideTip(event, '100', 709)" onmouseover="showTip(event, '100', 709)" class="fn">actualState</span><span class="pn">)</span> <span class="c">// load all past events to compute current state</span> <span class="c">// using snapshot if any</span> <span class="k">let</span> <span onmouseout="hideTip(event, '86', 710)" onmouseover="showTip(event, '86', 710)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 711)" onmouseover="showTip(event, '60', 711)" class="fn">state</span> <span class="o">=</span> <span onmouseout="hideTip(event, '110', 712)" onmouseover="showTip(event, '110', 712)" class="fn">loadState</span> <span onmouseout="hideTip(event, '85', 713)" onmouseover="showTip(event, '85', 713)" class="fn">stream</span> <span onmouseout="hideTip(event, '104', 714)" onmouseover="showTip(event, '104', 714)" class="fn">handle</span> <span class="pn">(</span><span onmouseout="hideTip(event, '86', 715)" onmouseover="showTip(event, '86', 715)" class="fn">version</span><span class="pn">,</span> <span onmouseout="hideTip(event, '60', 716)" onmouseover="showTip(event, '60', 716)" class="fn">state</span><span class="pn">)</span> </code></pre> <h2><a name="Conclusion" class="anchor" href="#Conclusion">Conclusion</a></h2> <p>You may have noticed that all the infrastructure code we wrote to run the Decider is totally agnostic of the actual Domain Code. It could be running a simple game or a complex business system, it will still stay the same.</p> <p>The other interesting point is that decider can be run in many ways. Purely in memory, storing state in a database or an event store. No changes to the domain code were required. This indicates a high level of independence from infrastructure concerns.</p> <p>You can write the Domain code as Deciders, and choose afterward which kind of persistence you want to use, if any.</p> <p>The last interesting point, is that Deciders can be composed. But that's another story...</p> <p><em>Credits: Special thanks to Greg Young and Ruben Bartelink, Adam Dymitruk and Mathias Verraes for their time and insight on the topic.</em></p> <div class="fsdocs-tip" id="1">namespace System</div> <div class="fsdocs-tip" id="2">Multiple items<br />union case Action.Action: Action<br /><br />--------------------<br />type Action = | Action<br /><br />--------------------<br />type Action&lt;&#39;T&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: obj: &#39;T * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: obj: &#39;T -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has a single parameter and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;obj&quot;&gt;The parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T&quot;&gt;The type of the parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has two parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has three parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has four parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has five parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has six parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has seven parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has eight parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has nine parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 10 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10,&#39;T11&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 11 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg11&quot;&gt;The eleventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T11&quot;&gt;The type of the eleventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10,&#39;T11,&#39;T12&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 12 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg11&quot;&gt;The eleventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg12&quot;&gt;The twelfth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T11&quot;&gt;The type of the eleventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T12&quot;&gt;The type of the twelfth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10,&#39;T11,&#39;T12,&#39;T13&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 13 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg11&quot;&gt;The eleventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg12&quot;&gt;The twelfth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg13&quot;&gt;The thirteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T11&quot;&gt;The type of the eleventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T12&quot;&gt;The type of the twelfth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T13&quot;&gt;The type of the thirteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10,&#39;T11,&#39;T12,&#39;T13,&#39;T14&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * arg14: &#39;T14 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * arg14: &#39;T14 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 14 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg11&quot;&gt;The eleventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg12&quot;&gt;The twelfth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg13&quot;&gt;The thirteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg14&quot;&gt;The fourteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T11&quot;&gt;The type of the eleventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T12&quot;&gt;The type of the twelfth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T13&quot;&gt;The type of the thirteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T14&quot;&gt;The type of the fourteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10,&#39;T11,&#39;T12,&#39;T13,&#39;T14,&#39;T15&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * arg14: &#39;T14 * arg15: &#39;T15 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * arg14: &#39;T14 * arg15: &#39;T15 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 15 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg11&quot;&gt;The eleventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg12&quot;&gt;The twelfth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg13&quot;&gt;The thirteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg14&quot;&gt;The fourteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg15&quot;&gt;The fifteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T11&quot;&gt;The type of the eleventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T12&quot;&gt;The type of the twelfth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T13&quot;&gt;The type of the thirteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T14&quot;&gt;The type of the fourteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T15&quot;&gt;The type of the fifteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em><br /><br />--------------------<br />type Action&lt;&#39;T1,&#39;T2,&#39;T3,&#39;T4,&#39;T5,&#39;T6,&#39;T7,&#39;T8,&#39;T9,&#39;T10,&#39;T11,&#39;T12,&#39;T13,&#39;T14,&#39;T15,&#39;T16&gt; = new: object: obj * method: nativeint -&gt; unit member BeginInvoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * arg14: &#39;T14 * arg15: &#39;T15 * arg16: &#39;T16 * callback: AsyncCallback * object: obj -&gt; IAsyncResult member EndInvoke: result: IAsyncResult -&gt; unit member Invoke: arg1: &#39;T1 * arg2: &#39;T2 * arg3: &#39;T3 * arg4: &#39;T4 * arg5: &#39;T5 * arg6: &#39;T6 * arg7: &#39;T7 * arg8: &#39;T8 * arg9: &#39;T9 * arg10: &#39;T10 * arg11: &#39;T11 * arg12: &#39;T12 * arg13: &#39;T13 * arg14: &#39;T14 * arg15: &#39;T15 * arg16: &#39;T16 -&gt; unit<br /><em>&lt;summary&gt;Encapsulates a method that has 16 parameters and does not return a value.&lt;/summary&gt;<br />&lt;param name=&quot;arg1&quot;&gt;The first parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg2&quot;&gt;The second parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg3&quot;&gt;The third parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg4&quot;&gt;The fourth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg5&quot;&gt;The fifth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg6&quot;&gt;The sixth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg7&quot;&gt;The seventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg8&quot;&gt;The eighth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg9&quot;&gt;The ninth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg10&quot;&gt;The tenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg11&quot;&gt;The eleventh parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg12&quot;&gt;The twelfth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg13&quot;&gt;The thirteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg14&quot;&gt;The fourteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg15&quot;&gt;The fifteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;param name=&quot;arg16&quot;&gt;The sixteenth parameter of the method that this delegate encapsulates.&lt;/param&gt;<br />&lt;typeparam name=&quot;T1&quot;&gt;The type of the first parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T2&quot;&gt;The type of the second parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T3&quot;&gt;The type of the third parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T4&quot;&gt;The type of the fourth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T5&quot;&gt;The type of the fifth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T6&quot;&gt;The type of the sixth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T7&quot;&gt;The type of the seventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T8&quot;&gt;The type of the eighth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T9&quot;&gt;The type of the ninth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T10&quot;&gt;The type of the tenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T11&quot;&gt;The type of the eleventh parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T12&quot;&gt;The type of the twelfth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T13&quot;&gt;The type of the thirteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T14&quot;&gt;The type of the fourteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T15&quot;&gt;The type of the fifteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;<br />&lt;typeparam name=&quot;T16&quot;&gt;The type of the sixteenth parameter of the method that this delegate encapsulates.&lt;/typeparam&gt;</em></div> <div class="fsdocs-tip" id="3">Multiple items<br />union case State.State: State<br /><br />--------------------<br />type State = | State</div> <div class="fsdocs-tip" id="4">Multiple items<br />union case Output.Output: Output<br /><br />--------------------<br />type Output = | Output</div> <div class="fsdocs-tip" id="5">val subsystem: action: Action -&gt; state: State -&gt; State * Output list</div> <div class="fsdocs-tip" id="6">val action: Action</div> <div class="fsdocs-tip" id="7">val state: State</div> <div class="fsdocs-tip" id="8">type &#39;T list = List&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="9">Multiple items<br />union case Command.Command: Command<br /><br />--------------------<br />type Command = | Command</div> <div class="fsdocs-tip" id="10">Multiple items<br />union case Event.Event: Event<br /><br />--------------------<br />module Event from Microsoft.FSharp.Control<br /><br />--------------------<br />type Event = | Event<br /><br />--------------------<br />type Event&lt;&#39;T&gt; = new: unit -&gt; Event&lt;&#39;T&gt; member Trigger: arg: &#39;T -&gt; unit member Publish: IEvent&lt;&#39;T&gt;<br /><br />--------------------<br />type Event&lt;&#39;Delegate,&#39;Args (requires delegate and &#39;Delegate :&gt; Delegate and reference type)&gt; = new: unit -&gt; Event&lt;&#39;Delegate,&#39;Args&gt; member Trigger: sender: objnull * args: &#39;Args -&gt; unit member Publish: IEvent&lt;&#39;Delegate,&#39;Args&gt;<br /><br />--------------------<br />new: unit -&gt; Event&lt;&#39;T&gt;<br /><br />--------------------<br />new: unit -&gt; Event&lt;&#39;Delegate,&#39;Args&gt;</div> <div class="fsdocs-tip" id="11">type Decide = Command -&gt; State -&gt; Event list</div> <div class="fsdocs-tip" id="12">type Evolve = State -&gt; Event -&gt; State</div> <div class="fsdocs-tip" id="13">Multiple items<br />union case Card.Card: Card<br /><br />--------------------<br />type Card = | Card</div> <div class="fsdocs-tip" id="14">Multiple items<br />union case State.State: State<br /><br />--------------------<br />type State = | InitialState | Started of topCard: Card</div> <div class="fsdocs-tip" id="15">val initialState: State</div> <div class="fsdocs-tip" id="16">union case State.InitialState: State</div> <div class="fsdocs-tip" id="17">Multiple items<br />union case State.State: State<br /><br />--------------------<br />type State = { Started: bool TopCard: Card }</div> <div class="fsdocs-tip" id="18">type bool = Boolean</div> <div class="fsdocs-tip" id="19">module Unchecked from Microsoft.FSharp.Core.Operators</div> <div class="fsdocs-tip" id="20">val defaultof&lt;&#39;T&gt; : &#39;T</div> <div class="fsdocs-tip" id="21">type Command</div> <div class="fsdocs-tip" id="22">Multiple items<br />module Event from Microsoft.FSharp.Control<br /><br />--------------------<br />type Event<br /><br />--------------------<br />type Event&lt;&#39;T&gt; = new: unit -&gt; Event&lt;&#39;T&gt; member Trigger: arg: &#39;T -&gt; unit member Publish: IEvent&lt;&#39;T&gt;<br /><br />--------------------<br />type Event&lt;&#39;Delegate,&#39;Args (requires delegate and &#39;Delegate :&gt; Delegate and reference type)&gt; = new: unit -&gt; Event&lt;&#39;Delegate,&#39;Args&gt; member Trigger: sender: objnull * args: &#39;Args -&gt; unit member Publish: IEvent&lt;&#39;Delegate,&#39;Args&gt;<br /><br />--------------------<br />new: unit -&gt; Event&lt;&#39;T&gt;<br /><br />--------------------<br />new: unit -&gt; Event&lt;&#39;Delegate,&#39;Args&gt;</div> <div class="fsdocs-tip" id="23">type State</div> <div class="fsdocs-tip" id="24">val evolve: state: State -&gt; event: Event -&gt; State</div> <div class="fsdocs-tip" id="25">val event: Event</div> <div class="fsdocs-tip" id="26">val failwith: message: string -&gt; &#39;T</div> <div class="fsdocs-tip" id="27">val computeNextState: currentState: State -&gt; events: Event seq -&gt; State</div> <div class="fsdocs-tip" id="28">val currentState: State</div> <div class="fsdocs-tip" id="29">val events: Event seq</div> <div class="fsdocs-tip" id="30">val mutable state: State</div> <div class="fsdocs-tip" id="31">val fold: state: State -&gt; events: Event list -&gt; State</div> <div class="fsdocs-tip" id="32">val events: Event list</div> <div class="fsdocs-tip" id="33">val rest: Event list</div> <div class="fsdocs-tip" id="34">val newState: State</div> <div class="fsdocs-tip" id="35">val fld: f: (&#39;a -&gt; &#39;b -&gt; &#39;a) -&gt; s: &#39;a -&gt; es: &#39;b list -&gt; &#39;a</div> <div class="fsdocs-tip" id="36">val f: (&#39;a -&gt; &#39;b -&gt; &#39;a)</div> <div class="fsdocs-tip" id="37">val s: &#39;a</div> <div class="fsdocs-tip" id="38">val es: &#39;b list</div> <div class="fsdocs-tip" id="39">val e: &#39;b</div> <div class="fsdocs-tip" id="40">val ns: &#39;a</div> <div class="fsdocs-tip" id="41">Multiple items<br />module List from Microsoft.FSharp.Collections<br /><br />--------------------<br />type List&lt;&#39;T&gt; = | op_Nil | op_ColonColon of Head: &#39;T * Tail: &#39;T list interface IReadOnlyList&lt;&#39;T&gt; interface IReadOnlyCollection&lt;&#39;T&gt; interface IEnumerable interface IEnumerable&lt;&#39;T&gt; member Equals: List&lt;&#39;T&gt; * IEqualityComparer -&gt; bool member GetReverseIndex: rank: int * offset: int -&gt; int member GetSlice: startIndex: int option * endIndex: int option -&gt; &#39;T list static member Cons: head: &#39;T * tail: &#39;T list -&gt; &#39;T list member Head: &#39;T member IsEmpty: bool ...</div> <div class="fsdocs-tip" id="42">val fold&lt;&#39;T,&#39;State&gt; : folder: (&#39;State -&gt; &#39;T -&gt; &#39;State) -&gt; state: &#39;State -&gt; list: &#39;T list -&gt; &#39;State</div> <div class="fsdocs-tip" id="43">val append: list1: &#39;T list -&gt; list2: &#39;T list -&gt; &#39;T list</div> <div class="fsdocs-tip" id="44">type bool = System.Boolean</div> <div class="fsdocs-tip" id="45">type Decider&lt;&#39;c,&#39;e,&#39;s&gt; = { decide: (&#39;c -&gt; &#39;s -&gt; &#39;e list) evolve: (&#39;s -&gt; &#39;e -&gt; &#39;s) initialState: &#39;s isTerminal: (&#39;s -&gt; bool) }</div> <div class="fsdocs-tip" id="46">&#39;c</div> <div class="fsdocs-tip" id="47">&#39;e</div> <div class="fsdocs-tip" id="48">&#39;s</div> <div class="fsdocs-tip" id="49">val start: decider: Decider&lt;&#39;c,&#39;e,&#39;s&gt; -&gt; (&#39;c -&gt; &#39;e list)</div> <div class="fsdocs-tip" id="50">val decider: Decider&lt;&#39;c,&#39;e,&#39;s&gt;</div> <div class="fsdocs-tip" id="51">val mutable state: &#39;s</div> <div class="fsdocs-tip" id="52">Decider.initialState: &#39;s</div> <div class="fsdocs-tip" id="53">val command: &#39;c</div> <div class="fsdocs-tip" id="54">val events: &#39;e list</div> <div class="fsdocs-tip" id="55">Decider.decide: &#39;c -&gt; &#39;s -&gt; &#39;e list</div> <div class="fsdocs-tip" id="56">Decider.evolve: &#39;s -&gt; &#39;e -&gt; &#39;s</div> <div class="fsdocs-tip" id="57">val loadState: id: &#39;a -&gt; &#39;s</div> <div class="fsdocs-tip" id="58">val id: &#39;a</div> <div class="fsdocs-tip" id="59">val saveState: id: &#39;a * state: &#39;s -&gt; unit</div> <div class="fsdocs-tip" id="60">val state: &#39;s</div> <div class="fsdocs-tip" id="61">type unit = Unit</div> <div class="fsdocs-tip" id="62">val start: decider: Decider&lt;&#39;c,&#39;e,&#39;s&gt; -&gt; id: &#39;a -&gt; command: &#39;c -&gt; &#39;e list</div> <div class="fsdocs-tip" id="63">module Storage from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="64">val newState: &#39;s</div> <div class="fsdocs-tip" id="65">Multiple items<br />union case Etag.Etag: Etag<br /><br />--------------------<br />type Etag = | Etag</div> <div class="fsdocs-tip" id="66">val loadState: id: &#39;a -&gt; Etag * &#39;s</div> <div class="fsdocs-tip" id="67">val trySaveState: id: &#39;a * etag: Etag * state: &#39;s -&gt; bool</div> <div class="fsdocs-tip" id="68">val etag: Etag</div> <div class="fsdocs-tip" id="69">val handle: unit -&gt; &#39;e list</div> <div class="fsdocs-tip" id="70">module StorageWithEtag from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="71">val trySaveState: id: &#39;a * etag: Etag * state: &#39;s -&gt; Etag option</div> <div class="fsdocs-tip" id="72">type &#39;T option = Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="73">val start: decider: Decider&lt;&#39;c,&#39;e,&#39;s&gt; -&gt; (&#39;a -&gt; &#39;c -&gt; &#39;e list)</div> <div class="fsdocs-tip" id="74">val mutable etagAndState: Etag * &#39;s</div> <div class="fsdocs-tip" id="75">module StorageWithEtagAndRetry from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="76">val id: x: &#39;T -&gt; &#39;T</div> <div class="fsdocs-tip" id="77">val handle: etag: Etag * state: &#39;b -&gt; &#39;e list</div> <div class="fsdocs-tip" id="78">val state: &#39;b</div> <div class="fsdocs-tip" id="79">union case Option.Some: Value: &#39;T -&gt; Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="80">val newEtag: Etag</div> <div class="fsdocs-tip" id="81">union case Option.None: Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="82">type Version = int</div> <div class="fsdocs-tip" id="83">Multiple items<br />val int: value: &#39;T -&gt; int (requires member op_Explicit)<br /><br />--------------------<br />type int = int32<br /><br />--------------------<br />type int&lt;&#39;Measure&gt; = int</div> <div class="fsdocs-tip" id="84">val loadEvents: stream: &#39;a * version: Version -&gt; &#39;e list</div> <div class="fsdocs-tip" id="85">val stream: &#39;a</div> <div class="fsdocs-tip" id="86">val version: Version</div> <div class="fsdocs-tip" id="87">val appendEvents: stream: &#39;a * events: &#39;e list -&gt; &#39;b</div> <div class="fsdocs-tip" id="88">val start: decider: Decider&lt;&#39;c,&#39;e,&#39;s&gt; -&gt; stream: &#39;a -&gt; command: &#39;c -&gt; &#39;e list</div> <div class="fsdocs-tip" id="89">module EventStore from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="90">val loadEvents: stream: &#39;a -&gt; Version * &#39;e list</div> <div class="fsdocs-tip" id="91">val tryAppendEvents: stream: &#39;a * expectedVersion: Version * events: &#39;e list -&gt; Result&lt;Version,(Version * &#39;e list)&gt;</div> <div class="fsdocs-tip" id="92">val expectedVersion: Version</div> <div class="fsdocs-tip" id="93">Multiple items<br />module Result from Microsoft.FSharp.Core<br /><br />--------------------<br />[&lt;Struct&gt;] type Result&lt;&#39;T,&#39;TError&gt; = | Ok of ResultValue: &#39;T | Error of ErrorValue: &#39;TError member Equals: Result&lt;&#39;T,&#39;TError&gt; * IEqualityComparer -&gt; bool member IsError: bool member IsOk: bool</div> <div class="fsdocs-tip" id="94">val handle: version: Version -&gt; state: &#39;s -&gt; &#39;e list</div> <div class="fsdocs-tip" id="95">module EventStoreWithVersion from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="96">union case Result.Ok: ResultValue: &#39;T -&gt; Result&lt;&#39;T,&#39;TError&gt;</div> <div class="fsdocs-tip" id="97">union case Result.Error: ErrorValue: &#39;TError -&gt; Result&lt;&#39;T,&#39;TError&gt;</div> <div class="fsdocs-tip" id="98">val actualVersion: Version</div> <div class="fsdocs-tip" id="99">val catchupEvents: &#39;e list</div> <div class="fsdocs-tip" id="100">val actualState: &#39;s</div> <div class="fsdocs-tip" id="101">val pastEvents: &#39;e list</div> <div class="fsdocs-tip" id="102">val start: stream: &#39;a -&gt; decider: Decider&lt;&#39;c,&#39;e,&#39;s&gt; -&gt; (&#39;c -&gt; &#39;e list)</div> <div class="fsdocs-tip" id="103">val mutable versionAndState: Version * &#39;s</div> <div class="fsdocs-tip" id="104">val handle: version: Version * state: &#39;s -&gt; &#39;e list</div> <div class="fsdocs-tip" id="105">val newVersion: Version</div> <div class="fsdocs-tip" id="106">val tryLoadSnapshot: stream: &#39;a -&gt; (Version * &#39;s) option</div> <div class="fsdocs-tip" id="107">val saveSnapshot: stream: &#39;a * version: Version * state: &#39;s -&gt; unit</div> <div class="fsdocs-tip" id="108">val isTimeToSnapshot: version: &#39;a -&gt; bool</div> <div class="fsdocs-tip" id="109">val version: &#39;a</div> <div class="fsdocs-tip" id="110">val loadState: stream: &#39;b -&gt; Version * &#39;s</div> <div class="fsdocs-tip" id="111">val stream: &#39;b</div> <div class="fsdocs-tip" id="112">val snapVersion: Version</div> <div class="fsdocs-tip" id="113">val snapState: &#39;s</div> <div class="fsdocs-tip" id="114">module Snapshots from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="115">module Option from Microsoft.FSharp.Core</div> <div class="fsdocs-tip" id="116">val defaultValue: value: &#39;T -&gt; option: &#39;T option -&gt; &#39;T</div> <div class="fsdocs-tip" id="117">val tryLoadSnapshot: stream: &#39;a * container: &#39;b -&gt; (Version * &#39;s) option</div> <div class="fsdocs-tip" id="118">val container: &#39;b</div> <div class="fsdocs-tip" id="119">val saveSnapshot: stream: &#39;a * container: &#39;b * version: Version * state: &#39;s -&gt; unit</div> <div class="fsdocs-tip" id="120">val getContainerFromDecideHash: &#39;a -&gt; &#39;b</div> <div class="fsdocs-tip" id="121">module WithSnapshotsInContainers from 2021-12-17-functional-event-sourcing-decider</div> <div class="fsdocs-tip" id="122">val container: obj</div> <div class="fsdocs-tip" id="123">module SnapshotsWithContainer from 2021-12-17-functional-event-sourcing-decider</div> Applicative Computation Expressions - 3 urn:md5:55 cf163ac66 75314b3 0694e365fc5 2020-12-03T09:21:51.2547358+00:00 Jérémie Chassaing <p><em>this post is part of the <a href="https://sergeytihon.com/2020/10/22/f-advent-calendar-in-english-2020/">F# Advent Calendar 2020</a></em></p> <p>In this third installment of our series about <a href="https://thinkbeforecoding.com/post/2020/10/03/applicatives-irl">applicative</a> <a href="https://thinkbeforecoding.com/post/2020/10/07/applicative-computation-expressions">computation</a> <a href="https://thinkbeforecoding.com/post/2020/10/08/applicative-computation-expressions-2">experessions</a>, we'll jump to practice with Lego Mindstorm Ev3. This should demonstrate a non trivial, real life use case for applicatives.</p> <p>Even if you don't have a mindstorm set at home, follow this post. We'll mix binary protocols and category theory - lightly explained - to provide a nice and safe API.</p> <h2><a name="Mindstorm-control-over-bluetooth" class="anchor" href="#Mindstorm-control-over-bluetooth">Mindstorm control over bluetooth</a></h2> <p>A few years back, I wrote a quick fsx script to control lego mindstorm in F#. I worked again on it recently to port it to net5.0.</p> <p>Once paired and connected, the brick - the central component of Mindstom used to drive motors and read sensors - appears as a <strong>serial port</strong>, COM9 on my machine. If you're using a linux system, it should appear as /dev/ttyS9 (or another number).</p> <p><code>System.IO.SerialPort</code> is available directly in Net framework, and as a nuget in netcore and net5.0. Add the reference to your project, or use the #r nuget reference in a F# 5.0 script:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="pp">#r</span> <span class="s">&quot;nuget: System.IO.Ports&quot;</span> </code></pre> <p>We will read/write bytes using the <code>SerialPort</code> and <code>ReadOnlyMemory</code> buffers. We'll soon go in more details.</p> <h3><a name="Request-Response" class="anchor" href="#Request-Response">Request/Response</a></h3> <p>The most interesting part is the Request/Response mechanism used for sensors. We write the request on the serial port by using <code>port.Write</code>, but get the response through an notification of the <code>port.DataReceived</code> event.</p> <p>The request response is asynchronous, and it would be far easier to present it in the API as an Async construct.</p> <p>When sending a request, we must include a mandatory sequence number in int. This sequence number will the be transmitted in the corresponding response for correlation.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '1', 1)" onmouseover="showTip(event, '1', 1)" class="vt">Sequence</span> <span class="o">=</span> <span onmouseout="hideTip(event, '2', 2)" onmouseover="showTip(event, '2', 2)" class="vt">uint16</span> </code></pre> <p>We will use this sequence number and a <code>MailboxProcessor</code> to implement Async in a responseDispatcher. It accepts two kinds of messages.</p> <p><code>Request</code> contains a Sequence number and a callback to call when the response bytes are available.</p> <p><code>Forward</code> contains a Sequence number and corresponding bytes.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">open</span> <span onmouseout="hideTip(event, '3', 3)" onmouseover="showTip(event, '3', 3)" class="id">System</span> <span class="k">open</span> <span onmouseout="hideTip(event, '3', 4)" onmouseover="showTip(event, '3', 4)" class="id">System</span><span class="pn">.</span><span onmouseout="hideTip(event, '4', 5)" onmouseover="showTip(event, '4', 5)" class="id">Threading</span> <span class="k">open</span> <span onmouseout="hideTip(event, '3', 6)" onmouseover="showTip(event, '3', 6)" class="id">System</span><span class="pn">.</span><span onmouseout="hideTip(event, '5', 7)" onmouseover="showTip(event, '5', 7)" class="id">Text</span> <span class="k">open</span> <span onmouseout="hideTip(event, '3', 8)" onmouseover="showTip(event, '3', 8)" class="id">System</span><span class="pn">.</span><span onmouseout="hideTip(event, '6', 9)" onmouseover="showTip(event, '6', 9)" class="id">Buffers</span> <span class="k">open</span> <span onmouseout="hideTip(event, '3', 10)" onmouseover="showTip(event, '3', 10)" class="id">System</span><span class="pn">.</span><span onmouseout="hideTip(event, '6', 11)" onmouseover="showTip(event, '6', 11)" class="id">Buffers</span><span class="pn">.</span><span onmouseout="hideTip(event, '7', 12)" onmouseover="showTip(event, '7', 12)" class="id">Binary</span> <span class="k">type</span> <span onmouseout="hideTip(event, '8', 13)" onmouseover="showTip(event, '8', 13)" class="rt">Dispatch</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">Request</span> <span class="k">of</span> <span class="prop">sequence</span><span class="pn">:</span> <span onmouseout="hideTip(event, '1', 14)" onmouseover="showTip(event, '1', 14)" class="vt">Sequence</span> <span class="pn">*</span> <span class="pn">(</span><span onmouseout="hideTip(event, '9', 15)" onmouseover="showTip(event, '9', 15)" class="vt">ReadOnlyMemory</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 16)" onmouseover="showTip(event, '10', 16)" class="vt">byte</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '11', 17)" onmouseover="showTip(event, '11', 17)" class="rt">unit</span><span class="pn">)</span> <span class="pn">|</span> <span class="uc">Forward</span> <span class="k">of</span> <span class="prop">sequence</span><span class="pn">:</span> <span onmouseout="hideTip(event, '1', 18)" onmouseover="showTip(event, '1', 18)" class="vt">Sequence</span> <span class="pn">*</span> <span onmouseout="hideTip(event, '9', 19)" onmouseover="showTip(event, '9', 19)" class="vt">ReadOnlyMemory</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 20)" onmouseover="showTip(event, '10', 20)" class="vt">byte</span><span class="pn">&gt;</span> </code></pre> <p>The mailbox processor is using an async rec function to process messages. On a <code>Request</code> message, it adds the callback to a <code>Map</code> under the sequence number key. On a <code>Forward</code> message, it finds the callback corresponding to the sequence number and call it with the data:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '12', 21)" onmouseover="showTip(event, '12', 21)" class="fn">responseDispatcher</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '13', 22)" onmouseover="showTip(event, '13', 22)" class="d">MailboxProcessor</span><span class="pn">.</span><span onmouseout="hideTip(event, '14', 23)" onmouseover="showTip(event, '14', 23)" class="id">Start</span> <span class="o">&lt;|</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '15', 24)" onmouseover="showTip(event, '15', 24)" class="d">mailbox</span> <span class="k">-&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '16', 25)" onmouseover="showTip(event, '16', 25)" class="fn">loop</span> <span onmouseout="hideTip(event, '17', 26)" onmouseover="showTip(event, '17', 26)" class="fn">requests</span> <span class="o">=</span> <span onmouseout="hideTip(event, '18', 27)" onmouseover="showTip(event, '18', 27)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '19', 28)" onmouseover="showTip(event, '19', 28)" class="fn">message</span> <span class="o">=</span> <span onmouseout="hideTip(event, '15', 29)" onmouseover="showTip(event, '15', 29)" class="d">mailbox</span><span class="pn">.</span><span onmouseout="hideTip(event, '20', 30)" onmouseover="showTip(event, '20', 30)" class="id">Receive</span><span class="pn">(</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '21', 31)" onmouseover="showTip(event, '21', 31)" class="fn">newMap</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '19', 32)" onmouseover="showTip(event, '19', 32)" class="fn">message</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '22', 33)" onmouseover="showTip(event, '22', 33)" class="uc">Request</span><span class="pn">(</span><span onmouseout="hideTip(event, '23', 34)" onmouseover="showTip(event, '23', 34)" class="fn">sequence</span><span class="pn">,</span> <span onmouseout="hideTip(event, '24', 35)" onmouseover="showTip(event, '24', 35)" class="fn">reply</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '25', 36)" onmouseover="showTip(event, '25', 36)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '26', 37)" onmouseover="showTip(event, '26', 37)" class="id">add</span> <span onmouseout="hideTip(event, '23', 38)" onmouseover="showTip(event, '23', 38)" class="fn">sequence</span> <span onmouseout="hideTip(event, '24', 39)" onmouseover="showTip(event, '24', 39)" class="fn">reply</span> <span onmouseout="hideTip(event, '17', 40)" onmouseover="showTip(event, '17', 40)" class="fn">requests</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '27', 41)" onmouseover="showTip(event, '27', 41)" class="uc">Forward</span><span class="pn">(</span><span onmouseout="hideTip(event, '23', 42)" onmouseover="showTip(event, '23', 42)" class="fn">sequence</span><span class="pn">,</span> <span onmouseout="hideTip(event, '28', 43)" onmouseover="showTip(event, '28', 43)" class="fn">response</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">match</span> <span onmouseout="hideTip(event, '25', 44)" onmouseover="showTip(event, '25', 44)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '29', 45)" onmouseover="showTip(event, '29', 45)" class="id">tryFind</span> <span onmouseout="hideTip(event, '23', 46)" onmouseover="showTip(event, '23', 46)" class="fn">sequence</span> <span onmouseout="hideTip(event, '17', 47)" onmouseover="showTip(event, '17', 47)" class="fn">requests</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '30', 48)" onmouseover="showTip(event, '30', 48)" class="uc">Some</span> <span onmouseout="hideTip(event, '24', 49)" onmouseover="showTip(event, '24', 49)" class="fn">reply</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '24', 50)" onmouseover="showTip(event, '24', 50)" class="fn">reply</span> <span onmouseout="hideTip(event, '28', 51)" onmouseover="showTip(event, '28', 51)" class="fn">response</span> <span onmouseout="hideTip(event, '25', 52)" onmouseover="showTip(event, '25', 52)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '31', 53)" onmouseover="showTip(event, '31', 53)" class="id">remove</span> <span onmouseout="hideTip(event, '23', 54)" onmouseover="showTip(event, '23', 54)" class="fn">sequence</span> <span onmouseout="hideTip(event, '17', 55)" onmouseover="showTip(event, '17', 55)" class="fn">requests</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '32', 56)" onmouseover="showTip(event, '32', 56)" class="uc">None</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '17', 57)" onmouseover="showTip(event, '17', 57)" class="fn">requests</span> <span class="k">return!</span> <span onmouseout="hideTip(event, '16', 58)" onmouseover="showTip(event, '16', 58)" class="fn">loop</span> <span class="fn">newMap</span> <span class="pn">}</span> <span onmouseout="hideTip(event, '16', 59)" onmouseover="showTip(event, '16', 59)" class="fn">loop</span> <span onmouseout="hideTip(event, '25', 60)" onmouseover="showTip(event, '25', 60)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '33', 61)" onmouseover="showTip(event, '33', 61)" class="id">empty</span> </code></pre> <p>The callback in the <code>Request</code> message is create using <code>PostAndAsyncReply</code>. The result is an Async that is competed when the callback is called.</p> <p>With this in place we can implement the Brick:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '34', 62)" onmouseover="showTip(event, '34', 62)" class="d">Brick</span><span class="pn">(</span> <span onmouseout="hideTip(event, '35', 63)" onmouseover="showTip(event, '35', 63)" class="fn">name</span> <span class="pn">)</span> <span class="o">=</span> <span class="c">// create the port</span> <span class="k">let</span> <span onmouseout="hideTip(event, '36', 64)" onmouseover="showTip(event, '36', 64)" class="d">port</span> <span class="o">=</span> <span class="k">new</span> <span onmouseout="hideTip(event, '37', 65)" onmouseover="showTip(event, '37', 65)" class="id">IO</span><span class="pn">.</span><span onmouseout="hideTip(event, '38', 66)" onmouseover="showTip(event, '38', 66)" class="id">Ports</span><span class="pn">.</span><span onmouseout="hideTip(event, '39', 67)" onmouseover="showTip(event, '39', 67)" class="id">SerialPort</span><span class="pn">(</span><span onmouseout="hideTip(event, '35', 68)" onmouseover="showTip(event, '35', 68)" class="fn">name</span><span class="pn">,</span><span class="n">115200</span><span class="pn">)</span> <span class="c">// the dispatcher for request/response async</span> <span class="k">let</span> <span onmouseout="hideTip(event, '40', 69)" onmouseover="showTip(event, '40', 69)" class="d">dispatcher</span> <span class="o">=</span> <span onmouseout="hideTip(event, '12', 70)" onmouseover="showTip(event, '12', 70)" class="fn">responseDispatcher</span><span class="pn">(</span><span class="pn">)</span> <span class="c">// the mutable sequence number to provide unique numbers </span> <span class="k">let</span> <span class="k">mutable</span> <span onmouseout="hideTip(event, '41', 71)" onmouseover="showTip(event, '41', 71)" class="mv">sequence</span> <span class="o">=</span> <span class="n">0</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">Connect</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="c">// open the port</span> <span onmouseout="hideTip(event, '36', 72)" onmouseover="showTip(event, '36', 72)" class="d">port</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 73)" onmouseover="showTip(event, '42', 73)" class="id">Open</span><span class="pn">(</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '43', 74)" onmouseover="showTip(event, '43', 74)" class="d">reader</span> <span class="o">=</span> <span class="k">new</span> <span onmouseout="hideTip(event, '37', 75)" onmouseover="showTip(event, '37', 75)" class="id">IO</span><span class="pn">.</span><span onmouseout="hideTip(event, '44', 76)" onmouseover="showTip(event, '44', 76)" class="id">BinaryReader</span><span class="pn">(</span><span onmouseout="hideTip(event, '36', 77)" onmouseover="showTip(event, '36', 77)" class="d">port</span><span class="pn">.</span><span onmouseout="hideTip(event, '45', 78)" onmouseover="showTip(event, '45', 78)" class="id">BaseStream</span><span class="pn">)</span> <span class="c">// register to receive data notifications</span> <span onmouseout="hideTip(event, '36', 79)" onmouseover="showTip(event, '36', 79)" class="d">port</span><span class="pn">.</span><span onmouseout="hideTip(event, '46', 80)" onmouseover="showTip(event, '46', 80)" class="id">DataReceived</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '47', 81)" onmouseover="showTip(event, '47', 81)" class="m">Event</span><span class="pn">.</span><span onmouseout="hideTip(event, '48', 82)" onmouseover="showTip(event, '48', 82)" class="id">add</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '49', 83)" onmouseover="showTip(event, '49', 83)" class="fn">e</span> <span class="k">-&gt;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '49', 84)" onmouseover="showTip(event, '49', 84)" class="fn">e</span><span class="pn">.</span><span onmouseout="hideTip(event, '50', 85)" onmouseover="showTip(event, '50', 85)" class="id">EventType</span> <span class="o">=</span> <span onmouseout="hideTip(event, '37', 86)" onmouseover="showTip(event, '37', 86)" class="id">IO</span><span class="pn">.</span><span onmouseout="hideTip(event, '38', 87)" onmouseover="showTip(event, '38', 87)" class="id">Ports</span><span class="pn">.</span><span onmouseout="hideTip(event, '51', 88)" onmouseover="showTip(event, '51', 88)" class="en">SerialData</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 89)" onmouseover="showTip(event, '52', 89)" class="id">Chars</span> <span class="k">then</span> <span class="c">//the response start with the size</span> <span class="k">let</span> <span onmouseout="hideTip(event, '53', 90)" onmouseover="showTip(event, '53', 90)" class="fn">size</span> <span class="o">=</span> <span onmouseout="hideTip(event, '43', 91)" onmouseover="showTip(event, '43', 91)" class="d">reader</span><span class="pn">.</span><span onmouseout="hideTip(event, '54', 92)" onmouseover="showTip(event, '54', 92)" class="id">ReadInt16</span><span class="pn">(</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '55', 93)" onmouseover="showTip(event, '55', 93)" class="fn">response</span> <span class="o">=</span> <span onmouseout="hideTip(event, '43', 94)" onmouseover="showTip(event, '43', 94)" class="d">reader</span><span class="pn">.</span><span onmouseout="hideTip(event, '56', 95)" onmouseover="showTip(event, '56', 95)" class="id">ReadBytes</span><span class="pn">(</span><span onmouseout="hideTip(event, '57', 96)" onmouseover="showTip(event, '57', 96)" class="fn">int</span> <span onmouseout="hideTip(event, '53', 97)" onmouseover="showTip(event, '53', 97)" class="fn">size</span><span class="pn">)</span> <span class="c">// and contains the sequence number as first 2 bytes</span> <span class="k">let</span> <span onmouseout="hideTip(event, '58', 98)" onmouseover="showTip(event, '58', 98)" class="fn">sequence</span> <span class="o">=</span> <span onmouseout="hideTip(event, '59', 99)" onmouseover="showTip(event, '59', 99)" class="rt">BitConverter</span><span class="pn">.</span><span onmouseout="hideTip(event, '60', 100)" onmouseover="showTip(event, '60', 100)" class="id">ToUInt16</span><span class="pn">(</span><span onmouseout="hideTip(event, '55', 101)" onmouseover="showTip(event, '55', 101)" class="fn">response</span><span class="pn">,</span> <span class="n">0</span><span class="pn">)</span> <span class="c">// we can then send it to the dispatcher</span> <span onmouseout="hideTip(event, '40', 102)" onmouseover="showTip(event, '40', 102)" class="d">dispatcher</span><span class="pn">.</span><span onmouseout="hideTip(event, '61', 103)" onmouseover="showTip(event, '61', 103)" class="id">Post</span><span class="pn">(</span><span onmouseout="hideTip(event, '27', 104)" onmouseover="showTip(event, '27', 104)" class="uc">Forward</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 105)" onmouseover="showTip(event, '58', 105)" class="fn">sequence</span><span class="pn">,</span> <span onmouseout="hideTip(event, '9', 106)" onmouseover="showTip(event, '9', 106)" class="fn">ReadOnlyMemory</span> <span onmouseout="hideTip(event, '55', 107)" onmouseover="showTip(event, '55', 107)" class="fn">response</span><span class="pn">)</span><span class="pn">)</span> <span class="pn">)</span> <span class="c">// gets new sequence number</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">GetNextSequence</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '62', 108)" onmouseover="showTip(event, '62', 108)" class="rt">Interlocked</span><span class="pn">.</span><span onmouseout="hideTip(event, '63', 109)" onmouseover="showTip(event, '63', 109)" class="id">Increment</span><span class="pn">(</span><span class="o">&amp;</span><span onmouseout="hideTip(event, '41', 110)" onmouseover="showTip(event, '41', 110)" class="mv">sequence</span><span class="pn">)</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '64', 111)" onmouseover="showTip(event, '64', 111)" class="fn">uint16</span> <span class="c">// write to the SerialPort</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">AsyncWrite</span> <span class="pn">(</span><span onmouseout="hideTip(event, '65', 112)" onmouseover="showTip(event, '65', 112)" class="fn">data</span><span class="pn">:</span> <span onmouseout="hideTip(event, '9', 113)" onmouseover="showTip(event, '9', 113)" class="vt">ReadOnlyMemory</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 114)" onmouseover="showTip(event, '10', 114)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '66', 115)" onmouseover="showTip(event, '66', 115)" class="fn">task</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 116)" onmouseover="showTip(event, '36', 116)" class="d">port</span><span class="pn">.</span><span onmouseout="hideTip(event, '45', 117)" onmouseover="showTip(event, '45', 117)" class="prop">BaseStream</span><span class="pn">.</span><span onmouseout="hideTip(event, '67', 118)" onmouseover="showTip(event, '67', 118)" class="id">WriteAsync</span><span class="pn">(</span><span onmouseout="hideTip(event, '65', 119)" onmouseover="showTip(event, '65', 119)" class="fn">data</span><span class="pn">)</span> <span class="c">// check synchronously if the ValueTask is completed</span> <span class="k">if</span> <span onmouseout="hideTip(event, '66', 120)" onmouseover="showTip(event, '66', 120)" class="fn">task</span><span class="pn">.</span><span onmouseout="hideTip(event, '68', 121)" onmouseover="showTip(event, '68', 121)" class="id">IsCompleted</span> <span class="k">then</span> <span onmouseout="hideTip(event, '18', 122)" onmouseover="showTip(event, '18', 122)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '69', 123)" onmouseover="showTip(event, '69', 123)" class="id">Return</span> <span class="pn">(</span><span class="pn">)</span> <span class="k">else</span> <span class="c">// else fallback on Task</span> <span onmouseout="hideTip(event, '70', 124)" onmouseover="showTip(event, '70', 124)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '71', 125)" onmouseover="showTip(event, '71', 125)" class="id">AwaitTask</span> <span class="pn">(</span><span onmouseout="hideTip(event, '66', 126)" onmouseover="showTip(event, '66', 126)" class="fn">task</span><span class="pn">.</span><span onmouseout="hideTip(event, '72', 127)" onmouseover="showTip(event, '72', 127)" class="id">AsTask</span><span class="pn">(</span><span class="pn">)</span><span class="pn">)</span> <span class="c">// send a request using specified sequence number</span> <span class="c">// and await the corresponding response</span> <span class="k">member</span> <span onmouseout="hideTip(event, '73', 128)" onmouseover="showTip(event, '73', 128)" class="d">this</span><span class="pn">.</span><span class="fn">AsyncRequest</span><span class="pn">(</span><span onmouseout="hideTip(event, '23', 129)" onmouseover="showTip(event, '23', 129)" class="fn">sequence</span><span class="pn">,</span> <span onmouseout="hideTip(event, '65', 130)" onmouseover="showTip(event, '65', 130)" class="fn">data</span><span class="pn">:</span> <span onmouseout="hideTip(event, '9', 131)" onmouseover="showTip(event, '9', 131)" class="vt">ReadOnlyMemory</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 132)" onmouseover="showTip(event, '10', 132)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '18', 133)" onmouseover="showTip(event, '18', 133)" class="k">async</span> <span class="pn">{</span> <span class="k">do!</span> <span onmouseout="hideTip(event, '73', 134)" onmouseover="showTip(event, '73', 134)" class="d">this</span><span class="pn">.</span><span onmouseout="hideTip(event, '74', 135)" onmouseover="showTip(event, '74', 135)" class="id">AsyncWrite</span><span class="pn">(</span><span onmouseout="hideTip(event, '65', 136)" onmouseover="showTip(event, '65', 136)" class="fn">data</span><span class="pn">)</span> <span class="k">return!</span> <span onmouseout="hideTip(event, '40', 137)" onmouseover="showTip(event, '40', 137)" class="d">dispatcher</span><span class="pn">.</span><span onmouseout="hideTip(event, '75', 138)" onmouseover="showTip(event, '75', 138)" class="id">PostAndAsyncReply</span><span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '76', 139)" onmouseover="showTip(event, '76', 139)" class="fn">reply</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '22', 140)" onmouseover="showTip(event, '22', 140)" class="uc">Request</span><span class="pn">(</span><span onmouseout="hideTip(event, '23', 141)" onmouseover="showTip(event, '23', 141)" class="fn">sequence</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '28', 142)" onmouseover="showTip(event, '28', 142)" class="fn">response</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '76', 143)" onmouseover="showTip(event, '76', 143)" class="fn">reply</span><span class="pn">.</span><span onmouseout="hideTip(event, '77', 144)" onmouseover="showTip(event, '77', 144)" class="id">Reply</span><span class="pn">(</span><span onmouseout="hideTip(event, '28', 145)" onmouseover="showTip(event, '28', 145)" class="fn">response</span><span class="pn">)</span><span class="pn">)</span><span class="pn">)</span> <span class="pn">}</span> <span class="k">interface</span> <span onmouseout="hideTip(event, '78', 146)" onmouseover="showTip(event, '78', 146)" class="if">IDisposable</span> <span class="k">with</span> <span class="k">member</span> <span class="id">__</span><span class="pn">.</span><span class="fn">Dispose</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 147)" onmouseover="showTip(event, '36', 147)" class="d">port</span><span class="pn">.</span><span onmouseout="hideTip(event, '79', 148)" onmouseover="showTip(event, '79', 148)" class="id">Close</span><span class="pn">(</span><span class="pn">)</span> </code></pre> <h2><a name="Commands-Serialization" class="anchor" href="#Commands-Serialization">Commands Serialization</a></h2> <p>Now that we can easily send bytes over the serial port, we need to serialize commands.</p> <p>the format is :</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="n">0</span> <span class="o">-</span> <span class="id">ushort</span> <span class="pn">:</span> <span class="id">bytes</span> <span class="id">size</span> <span class="n">2</span> <span class="o">-</span> <span class="id">ushort</span> <span class="pn">:</span> <span class="id">sequence</span> <span class="id">number</span> <span class="n">4</span> <span class="o">-</span> <span onmouseout="hideTip(event, '80', 149)" onmouseover="showTip(event, '80', 149)" class="id">byte</span> <span class="pn">:</span> <span class="id">command</span> <span class="k">type</span> <span class="pn">(</span><span class="id">direct</span><span class="o">/</span><span class="id">system</span><span class="pn">,</span> <span class="id">reply</span><span class="o">/</span><span class="id">noreply</span><span class="pn">)</span> <span class="n">5</span> <span class="o">-</span> <span class="id">ushort</span> <span class="pn">:</span> <span class="k">global</span> <span class="id">size</span> <span class="pn">(</span><span class="id">size</span> <span class="k">of</span> <span class="k">return</span> <span class="id">values</span><span class="pn">)</span> <span class="n">7</span> <span class="o">..</span><span class="pn">.</span> <span class="pn">:</span> <span class="id">commands</span> <span class="id">bytes</span> </code></pre> <p>It is possible to send several commands in a single call.</p> <h3><a name="Command-type" class="anchor" href="#Command-type">Command type</a></h3> <p>The command type is encoded on a single byte. bit 0 indicates whether it's a direct command (activating motors/sensors) or system command (uploading/downloading files). Bit 7 indicates whether we expect a reply. We'll not use system commands in this post.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">CommandType</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '81', 150)" onmouseover="showTip(event, '81', 150)" class="id">directReply</span> <span class="o">=</span> <span class="n">0x00uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '82', 151)" onmouseover="showTip(event, '82', 151)" class="id">directNoReply</span> <span class="o">=</span> <span class="n">0x80uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '83', 152)" onmouseover="showTip(event, '83', 152)" class="id">systemReply</span> <span class="o">=</span> <span class="n">0x01uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '84', 153)" onmouseover="showTip(event, '84', 153)" class="id">systemNoReply</span> <span class="o">=</span> <span class="n">0x81uy</span> </code></pre> <h3><a name="OpCode" class="anchor" href="#OpCode">OpCode</a></h3> <p>The type of command is indicated by a 1 or 2 bytes opcode. Here is an enum of the different opcodes supported by Ev3:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '85', 154)" onmouseover="showTip(event, '85', 154)" class="en">Opcode</span> <span class="o">=</span> <span class="pn">|</span> <span class="en">UIRead_GetFirmware</span> <span class="o">=</span> <span class="n">0x810a</span> <span class="pn">|</span> <span class="en">UIWrite_LED</span> <span class="o">=</span> <span class="n">0x821b</span> <span class="pn">|</span> <span class="en">UIButton_Pressed</span> <span class="o">=</span> <span class="n">0x8309</span> <span class="pn">|</span> <span class="en">UIDraw_Update</span> <span class="o">=</span> <span class="n">0x8400</span> <span class="pn">|</span> <span class="en">UIDraw_Clean</span> <span class="o">=</span> <span class="n">0x8401</span> <span class="pn">|</span> <span class="en">UIDraw_Pixel</span> <span class="o">=</span> <span class="n">0x8402</span> <span class="pn">|</span> <span class="en">UIDraw_Line</span> <span class="o">=</span> <span class="n">0x8403</span> <span class="pn">|</span> <span class="en">UIDraw_Circle</span> <span class="o">=</span> <span class="n">0x8404</span> <span class="pn">|</span> <span class="en">UIDraw_Text</span> <span class="o">=</span> <span class="n">0x8405</span> <span class="pn">|</span> <span class="en">UIDraw_FillRect</span> <span class="o">=</span> <span class="n">0x8409</span> <span class="pn">|</span> <span class="en">UIDraw_Rect</span> <span class="o">=</span> <span class="n">0x840a</span> <span class="pn">|</span> <span class="en">UIDraw_InverseRect</span> <span class="o">=</span> <span class="n">0x8410</span> <span class="pn">|</span> <span class="en">UIDraw_SelectFont</span> <span class="o">=</span> <span class="n">0x8411</span> <span class="pn">|</span> <span class="en">UIDraw_Topline</span> <span class="o">=</span> <span class="n">0x8412</span> <span class="pn">|</span> <span class="en">UIDraw_FillWindow</span> <span class="o">=</span> <span class="n">0x8413</span> <span class="pn">|</span> <span class="en">UIDraw_DotLine</span> <span class="o">=</span> <span class="n">0x8415</span> <span class="pn">|</span> <span class="en">UIDraw_FillCircle</span> <span class="o">=</span> <span class="n">0x8418</span> <span class="pn">|</span> <span class="en">UIDraw_BmpFile</span> <span class="o">=</span> <span class="n">0x841c</span> <span class="pn">|</span> <span class="en">Sound_Break</span> <span class="o">=</span> <span class="n">0x9400</span> <span class="pn">|</span> <span class="en">Sound_Tone</span> <span class="o">=</span> <span class="n">0x9401</span> <span class="pn">|</span> <span class="en">Sound_Play</span> <span class="o">=</span> <span class="n">0x9402</span> <span class="pn">|</span> <span class="en">Sound_Repeat</span> <span class="o">=</span> <span class="n">0x9403</span> <span class="pn">|</span> <span class="en">Sound_Service</span> <span class="o">=</span> <span class="n">0x9404</span> <span class="pn">|</span> <span class="en">InputDevice_GetTypeMode</span> <span class="o">=</span> <span class="n">0x9905</span> <span class="pn">|</span> <span class="en">InputDevice_GetDeviceName</span> <span class="o">=</span> <span class="n">0x9915</span> <span class="pn">|</span> <span class="en">InputDevice_GetModeName</span> <span class="o">=</span> <span class="n">0x9916</span> <span class="pn">|</span> <span class="en">InputDevice_ReadyPct</span> <span class="o">=</span> <span class="n">0x991b</span> <span class="pn">|</span> <span class="en">InputDevice_ReadyRaw</span> <span class="o">=</span> <span class="n">0x991c</span> <span class="pn">|</span> <span class="en">InputDevice_ReadySI</span> <span class="o">=</span> <span class="n">0x991d</span> <span class="pn">|</span> <span class="en">InputDevice_ClearAll</span> <span class="o">=</span> <span class="n">0x990a</span> <span class="pn">|</span> <span class="en">InputDevice_ClearChanges</span> <span class="o">=</span> <span class="n">0x991a</span> <span class="pn">|</span> <span class="en">InputRead</span> <span class="o">=</span> <span class="n">0x9a</span> <span class="pn">|</span> <span class="en">InputReadExt</span> <span class="o">=</span> <span class="n">0x9e</span> <span class="pn">|</span> <span class="en">InputReadSI</span> <span class="o">=</span> <span class="n">0x9d</span> <span class="pn">|</span> <span class="en">OutputStop</span> <span class="o">=</span> <span class="n">0xa3</span> <span class="pn">|</span> <span class="en">OutputPower</span> <span class="o">=</span> <span class="n">0xa4</span> <span class="pn">|</span> <span class="en">OutputSpeed</span> <span class="o">=</span> <span class="n">0xa5</span> <span class="pn">|</span> <span class="en">OutputStart</span> <span class="o">=</span> <span class="n">0xa6</span> <span class="pn">|</span> <span class="en">OutputPolarity</span> <span class="o">=</span> <span class="n">0xa7</span> <span class="pn">|</span> <span class="en">OutputReady</span> <span class="o">=</span> <span class="n">0xaa</span> <span class="pn">|</span> <span class="en">OutputStepPower</span> <span class="o">=</span> <span class="n">0xac</span> <span class="pn">|</span> <span class="en">OutputTimePower</span> <span class="o">=</span> <span class="n">0xad</span> <span class="pn">|</span> <span class="en">OutputStepSpeed</span> <span class="o">=</span> <span class="n">0xae</span> <span class="pn">|</span> <span class="en">OutputTimeSpeed</span> <span class="o">=</span> <span class="n">0xaf</span> <span class="pn">|</span> <span class="en">OutputStepSync</span> <span class="o">=</span> <span class="n">0xb0</span> <span class="pn">|</span> <span class="en">OutputTimeSync</span> <span class="o">=</span> <span class="n">0xb1</span> </code></pre> <p>and the list of system opcodes (not used)</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '86', 155)" onmouseover="showTip(event, '86', 155)" class="en">SystemOpcode</span> <span class="o">=</span> <span class="pn">|</span> <span class="en">BeginDownload</span> <span class="o">=</span> <span class="n">0x92</span> <span class="pn">|</span> <span class="en">ContinueDownload</span> <span class="o">=</span> <span class="n">0x93</span> <span class="pn">|</span> <span class="en">CloseFileHandle</span> <span class="o">=</span> <span class="n">0x98</span> <span class="pn">|</span> <span class="en">CreateDirectory</span> <span class="o">=</span> <span class="n">0x9b</span> <span class="pn">|</span> <span class="en">DeleteFile</span> <span class="o">=</span> <span class="n">0x9c</span> </code></pre> <p>To help with the serialization in a Span<T> we define some inline helpers:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span onmouseout="hideTip(event, '87', 156)" onmouseover="showTip(event, '87', 156)" class="m">Buffer</span> <span class="o">=</span> <span class="k">let</span> <span class="k">inline</span> <span onmouseout="hideTip(event, '88', 157)" onmouseover="showTip(event, '88', 157)" class="fn">write</span> <span onmouseout="hideTip(event, '89', 158)" onmouseover="showTip(event, '89', 158)" class="fn">value</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 159)" onmouseover="showTip(event, '90', 159)" class="fn">buffer</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 160)" onmouseover="showTip(event, '10', 160)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '90', 161)" onmouseover="showTip(event, '90', 161)" class="fn">buffer</span><span class="pn">.</span><span class="pn">[</span><span class="n">0</span><span class="pn">]</span> <span class="k">&lt;-</span> <span onmouseout="hideTip(event, '89', 162)" onmouseover="showTip(event, '89', 162)" class="fn">value</span> <span onmouseout="hideTip(event, '90', 163)" onmouseover="showTip(event, '90', 163)" class="fn">buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 164)" onmouseover="showTip(event, '91', 164)" class="id">Slice</span><span class="pn">(</span><span class="n">1</span><span class="pn">)</span> <span class="k">let</span> <span class="k">inline</span> <span onmouseout="hideTip(event, '92', 165)" onmouseover="showTip(event, '92', 165)" class="fn">writeUint16</span> <span class="pn">(</span><span onmouseout="hideTip(event, '93', 166)" onmouseover="showTip(event, '93', 166)" class="fn">value</span><span class="pn">:</span><span onmouseout="hideTip(event, '64', 167)" onmouseover="showTip(event, '64', 167)" class="vt">uint16</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 168)" onmouseover="showTip(event, '90', 168)" class="fn">buffer</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 169)" onmouseover="showTip(event, '10', 169)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '94', 170)" onmouseover="showTip(event, '94', 170)" class="rt">BinaryPrimitives</span><span class="pn">.</span><span onmouseout="hideTip(event, '95', 171)" onmouseover="showTip(event, '95', 171)" class="id">WriteUInt16LittleEndian</span><span class="pn">(</span><span onmouseout="hideTip(event, '90', 172)" onmouseover="showTip(event, '90', 172)" class="fn">buffer</span><span class="pn">,</span> <span onmouseout="hideTip(event, '93', 173)" onmouseover="showTip(event, '93', 173)" class="fn">value</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 174)" onmouseover="showTip(event, '90', 174)" class="fn">buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 175)" onmouseover="showTip(event, '91', 175)" class="id">Slice</span><span class="pn">(</span><span class="n">2</span><span class="pn">)</span> <span class="k">let</span> <span class="k">inline</span> <span onmouseout="hideTip(event, '96', 176)" onmouseover="showTip(event, '96', 176)" class="fn">writeUint16BE</span> <span class="pn">(</span><span onmouseout="hideTip(event, '93', 177)" onmouseover="showTip(event, '93', 177)" class="fn">value</span><span class="pn">:</span><span onmouseout="hideTip(event, '64', 178)" onmouseover="showTip(event, '64', 178)" class="vt">uint16</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 179)" onmouseover="showTip(event, '90', 179)" class="fn">buffer</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 180)" onmouseover="showTip(event, '10', 180)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '94', 181)" onmouseover="showTip(event, '94', 181)" class="rt">BinaryPrimitives</span><span class="pn">.</span><span onmouseout="hideTip(event, '97', 182)" onmouseover="showTip(event, '97', 182)" class="id">WriteUInt16BigEndian</span><span class="pn">(</span><span onmouseout="hideTip(event, '90', 183)" onmouseover="showTip(event, '90', 183)" class="fn">buffer</span><span class="pn">,</span> <span onmouseout="hideTip(event, '93', 184)" onmouseover="showTip(event, '93', 184)" class="fn">value</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 185)" onmouseover="showTip(event, '90', 185)" class="fn">buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 186)" onmouseover="showTip(event, '91', 186)" class="id">Slice</span><span class="pn">(</span><span class="n">2</span><span class="pn">)</span> <span class="k">let</span> <span class="k">inline</span> <span onmouseout="hideTip(event, '98', 187)" onmouseover="showTip(event, '98', 187)" class="fn">writeUInt32</span> <span class="pn">(</span><span onmouseout="hideTip(event, '99', 188)" onmouseover="showTip(event, '99', 188)" class="fn">value</span><span class="pn">:</span><span onmouseout="hideTip(event, '100', 189)" onmouseover="showTip(event, '100', 189)" class="vt">uint32</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 190)" onmouseover="showTip(event, '90', 190)" class="fn">buffer</span><span class="pn">:</span><span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 191)" onmouseover="showTip(event, '10', 191)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '94', 192)" onmouseover="showTip(event, '94', 192)" class="rt">BinaryPrimitives</span><span class="pn">.</span><span onmouseout="hideTip(event, '101', 193)" onmouseover="showTip(event, '101', 193)" class="id">WriteUInt32LittleEndian</span><span class="pn">(</span><span onmouseout="hideTip(event, '90', 194)" onmouseover="showTip(event, '90', 194)" class="fn">buffer</span><span class="pn">,</span> <span onmouseout="hideTip(event, '99', 195)" onmouseover="showTip(event, '99', 195)" class="fn">value</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 196)" onmouseover="showTip(event, '90', 196)" class="fn">buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 197)" onmouseover="showTip(event, '91', 197)" class="id">Slice</span><span class="pn">(</span><span class="n">4</span><span class="pn">)</span> <span class="k">let</span> <span class="k">inline</span> <span onmouseout="hideTip(event, '102', 198)" onmouseover="showTip(event, '102', 198)" class="fn">writeString</span> <span class="pn">(</span><span onmouseout="hideTip(event, '103', 199)" onmouseover="showTip(event, '103', 199)" class="fn">s</span><span class="pn">:</span> <span onmouseout="hideTip(event, '104', 200)" onmouseover="showTip(event, '104', 200)" class="rt">string</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 201)" onmouseover="showTip(event, '90', 201)" class="fn">buffer</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 202)" onmouseover="showTip(event, '10', 202)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '105', 203)" onmouseover="showTip(event, '105', 203)" class="fn">len</span> <span class="o">=</span> <span onmouseout="hideTip(event, '106', 204)" onmouseover="showTip(event, '106', 204)" class="rt">Encoding</span><span class="pn">.</span><span onmouseout="hideTip(event, '107', 205)" onmouseover="showTip(event, '107', 205)" class="id">UTF8</span><span class="pn">.</span><span onmouseout="hideTip(event, '108', 206)" onmouseover="showTip(event, '108', 206)" class="id">GetBytes</span><span class="pn">(</span><span onmouseout="hideTip(event, '103', 207)" onmouseover="showTip(event, '103', 207)" class="fn">s</span><span class="pn">.</span><span onmouseout="hideTip(event, '109', 208)" onmouseover="showTip(event, '109', 208)" class="id">AsSpan</span><span class="pn">(</span><span class="pn">)</span><span class="pn">,</span> <span onmouseout="hideTip(event, '90', 209)" onmouseover="showTip(event, '90', 209)" class="fn">buffer</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 210)" onmouseover="showTip(event, '90', 210)" class="fn">buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '91', 211)" onmouseover="showTip(event, '91', 211)" class="id">Slice</span><span class="pn">(</span><span onmouseout="hideTip(event, '105', 212)" onmouseover="showTip(event, '105', 212)" class="fn">len</span><span class="pn">)</span> </code></pre> <p>Each of these functions writes a value at the beginning of the span and slices the appropriate size to return a new span starting just after the value that was just written.</p> <p>Using this we can write the serializeOpcode function:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '110', 213)" onmouseover="showTip(event, '110', 213)" class="fn">serializeOpcode</span> <span onmouseout="hideTip(event, '111', 214)" onmouseover="showTip(event, '111', 214)" class="fn">op</span> <span onmouseout="hideTip(event, '90', 215)" onmouseover="showTip(event, '90', 215)" class="fn">buffer</span> <span class="o">=</span> <span class="k">if</span> <span onmouseout="hideTip(event, '111', 216)" onmouseover="showTip(event, '111', 216)" class="fn">op</span> <span class="o">&gt;</span> <span onmouseout="hideTip(event, '112', 217)" onmouseover="showTip(event, '112', 217)" class="fn">enum</span> <span class="n">0xff</span> <span class="k">then</span> <span class="c">// this is a 2 bytes opcode</span> <span class="c">// it is serialized in big endian format</span> <span onmouseout="hideTip(event, '87', 218)" onmouseover="showTip(event, '87', 218)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '96', 219)" onmouseover="showTip(event, '96', 219)" class="id">writeUint16BE</span> <span class="pn">(</span><span onmouseout="hideTip(event, '64', 220)" onmouseover="showTip(event, '64', 220)" class="fn">uint16</span> <span onmouseout="hideTip(event, '111', 221)" onmouseover="showTip(event, '111', 221)" class="fn">op</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 222)" onmouseover="showTip(event, '90', 222)" class="fn">buffer</span> <span class="k">else</span> <span class="c">// this is a 1 byte opode</span> <span onmouseout="hideTip(event, '87', 223)" onmouseover="showTip(event, '87', 223)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 224)" onmouseover="showTip(event, '88', 224)" class="id">write</span> <span class="pn">(</span><span onmouseout="hideTip(event, '10', 225)" onmouseover="showTip(event, '10', 225)" class="fn">byte</span> <span onmouseout="hideTip(event, '111', 226)" onmouseover="showTip(event, '111', 226)" class="fn">op</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 227)" onmouseover="showTip(event, '90', 227)" class="fn">buffer</span> </code></pre> <p>In order to allocate the buffer, we need to compute the total size. The following functions returns the size for an opcode:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '113', 228)" onmouseover="showTip(event, '113', 228)" class="fn">opcodeLength</span> <span onmouseout="hideTip(event, '114', 229)" onmouseover="showTip(event, '114', 229)" class="fn">code</span> <span class="o">=</span> <span class="k">if</span> <span onmouseout="hideTip(event, '114', 230)" onmouseover="showTip(event, '114', 230)" class="fn">code</span> <span class="o">&gt;</span> <span onmouseout="hideTip(event, '112', 231)" onmouseover="showTip(event, '112', 231)" class="fn">enum</span> <span class="n">0xff</span> <span class="k">then</span> <span class="n">2</span> <span class="k">else</span> <span class="n">1</span> </code></pre> <h3><a name="Parameters" class="anchor" href="#Parameters">Parameters</a></h3> <p>Each opcode is followed by a given number of parameters containing the mandatory values for the operation.</p> <p>We define a union type to represents different parameter types and their values:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '115', 232)" onmouseover="showTip(event, '115', 232)" class="rt">Parameter</span> <span class="o">=</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '116', 233)" onmouseover="showTip(event, '116', 233)" class="uc">Byte</span> <span class="k">of</span> <span onmouseout="hideTip(event, '117', 234)" onmouseover="showTip(event, '117', 234)" class="vt">uint8</span> <span class="pn">|</span> <span class="uc">UShort</span> <span class="k">of</span> <span onmouseout="hideTip(event, '64', 235)" onmouseover="showTip(event, '64', 235)" class="vt">uint16</span> <span class="pn">|</span> <span class="uc">UInt</span> <span class="k">of</span> <span onmouseout="hideTip(event, '100', 236)" onmouseover="showTip(event, '100', 236)" class="vt">uint32</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '118', 237)" onmouseover="showTip(event, '118', 237)" class="uc">String</span> <span class="k">of</span> <span onmouseout="hideTip(event, '104', 238)" onmouseover="showTip(event, '104', 238)" class="rt">string</span> <span class="pn">|</span> <span class="uc">GlobalIndex</span> <span class="k">of</span> <span onmouseout="hideTip(event, '117', 239)" onmouseover="showTip(event, '117', 239)" class="vt">uint8</span> </code></pre> <p>All types are pretty explicit except the last one. GlobalIndex is used to indicate a byte offset in a response data. We'll use it later.</p> <p>Each argument is composed of a 1 byte prefix indicating it's type/size, followed by the value itself. Here are the different prefixes:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">ParamSize</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '119', 240)" onmouseover="showTip(event, '119', 240)" class="id">byte</span> <span class="o">=</span> <span class="n">0x81uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '120', 241)" onmouseover="showTip(event, '120', 241)" class="id">short</span> <span class="o">=</span> <span class="n">0x82uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '121', 242)" onmouseover="showTip(event, '121', 242)" class="id">int</span> <span class="o">=</span> <span class="n">0x83uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '122', 243)" onmouseover="showTip(event, '122', 243)" class="id">string</span> <span class="o">=</span> <span class="n">0x84uy</span> <span class="k">let</span> <span onmouseout="hideTip(event, '123', 244)" onmouseover="showTip(event, '123', 244)" class="id">globalIndex</span> <span class="o">=</span> <span class="n">0xe1uy</span> </code></pre> <p>Now we can serialize a parameter and get its length:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '124', 245)" onmouseover="showTip(event, '124', 245)" class="fn">serializeParam</span> <span onmouseout="hideTip(event, '125', 246)" onmouseover="showTip(event, '125', 246)" class="fn">p</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 247)" onmouseover="showTip(event, '90', 247)" class="fn">buffer</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 248)" onmouseover="showTip(event, '10', 248)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '125', 249)" onmouseover="showTip(event, '125', 249)" class="fn">p</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '126', 250)" onmouseover="showTip(event, '126', 250)" class="uc">Byte</span> <span onmouseout="hideTip(event, '127', 251)" onmouseover="showTip(event, '127', 251)" class="fn">v</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 252)" onmouseover="showTip(event, '128', 252)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 253)" onmouseover="showTip(event, '87', 253)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 254)" onmouseover="showTip(event, '88', 254)" class="id">write</span> <span onmouseout="hideTip(event, '129', 255)" onmouseover="showTip(event, '129', 255)" class="m">ParamSize</span><span class="pn">.</span><span onmouseout="hideTip(event, '130', 256)" onmouseover="showTip(event, '130', 256)" class="id">byte</span> <span onmouseout="hideTip(event, '90', 257)" onmouseover="showTip(event, '90', 257)" class="fn">buffer</span> <span onmouseout="hideTip(event, '87', 258)" onmouseover="showTip(event, '87', 258)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 259)" onmouseover="showTip(event, '88', 259)" class="id">write</span> <span onmouseout="hideTip(event, '127', 260)" onmouseover="showTip(event, '127', 260)" class="fn">v</span> <span onmouseout="hideTip(event, '128', 261)" onmouseover="showTip(event, '128', 261)" class="fn">b</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '131', 262)" onmouseover="showTip(event, '131', 262)" class="uc">UShort</span> <span onmouseout="hideTip(event, '132', 263)" onmouseover="showTip(event, '132', 263)" class="fn">v</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 264)" onmouseover="showTip(event, '128', 264)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 265)" onmouseover="showTip(event, '87', 265)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 266)" onmouseover="showTip(event, '88', 266)" class="id">write</span> <span onmouseout="hideTip(event, '129', 267)" onmouseover="showTip(event, '129', 267)" class="m">ParamSize</span><span class="pn">.</span><span onmouseout="hideTip(event, '120', 268)" onmouseover="showTip(event, '120', 268)" class="id">short</span> <span onmouseout="hideTip(event, '90', 269)" onmouseover="showTip(event, '90', 269)" class="fn">buffer</span> <span onmouseout="hideTip(event, '87', 270)" onmouseover="showTip(event, '87', 270)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '92', 271)" onmouseover="showTip(event, '92', 271)" class="id">writeUint16</span> <span onmouseout="hideTip(event, '132', 272)" onmouseover="showTip(event, '132', 272)" class="fn">v</span> <span onmouseout="hideTip(event, '128', 273)" onmouseover="showTip(event, '128', 273)" class="fn">b</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '133', 274)" onmouseover="showTip(event, '133', 274)" class="uc">UInt</span> <span onmouseout="hideTip(event, '134', 275)" onmouseover="showTip(event, '134', 275)" class="fn">v</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 276)" onmouseover="showTip(event, '128', 276)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 277)" onmouseover="showTip(event, '87', 277)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 278)" onmouseover="showTip(event, '88', 278)" class="id">write</span> <span onmouseout="hideTip(event, '129', 279)" onmouseover="showTip(event, '129', 279)" class="m">ParamSize</span><span class="pn">.</span><span onmouseout="hideTip(event, '135', 280)" onmouseover="showTip(event, '135', 280)" class="id">int</span> <span onmouseout="hideTip(event, '90', 281)" onmouseover="showTip(event, '90', 281)" class="fn">buffer</span> <span onmouseout="hideTip(event, '87', 282)" onmouseover="showTip(event, '87', 282)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '98', 283)" onmouseover="showTip(event, '98', 283)" class="id">writeUInt32</span> <span onmouseout="hideTip(event, '134', 284)" onmouseover="showTip(event, '134', 284)" class="fn">v</span> <span onmouseout="hideTip(event, '128', 285)" onmouseover="showTip(event, '128', 285)" class="fn">b</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '136', 286)" onmouseover="showTip(event, '136', 286)" class="uc">String</span> <span onmouseout="hideTip(event, '103', 287)" onmouseover="showTip(event, '103', 287)" class="fn">s</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 288)" onmouseover="showTip(event, '128', 288)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 289)" onmouseover="showTip(event, '87', 289)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 290)" onmouseover="showTip(event, '88', 290)" class="id">write</span> <span onmouseout="hideTip(event, '129', 291)" onmouseover="showTip(event, '129', 291)" class="m">ParamSize</span><span class="pn">.</span><span onmouseout="hideTip(event, '137', 292)" onmouseover="showTip(event, '137', 292)" class="id">string</span> <span onmouseout="hideTip(event, '90', 293)" onmouseover="showTip(event, '90', 293)" class="fn">buffer</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 294)" onmouseover="showTip(event, '128', 294)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 295)" onmouseover="showTip(event, '87', 295)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '102', 296)" onmouseover="showTip(event, '102', 296)" class="id">writeString</span> <span onmouseout="hideTip(event, '103', 297)" onmouseover="showTip(event, '103', 297)" class="fn">s</span> <span onmouseout="hideTip(event, '128', 298)" onmouseover="showTip(event, '128', 298)" class="fn">b</span> <span onmouseout="hideTip(event, '87', 299)" onmouseover="showTip(event, '87', 299)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 300)" onmouseover="showTip(event, '88', 300)" class="id">write</span> <span class="n">0uy</span> <span onmouseout="hideTip(event, '128', 301)" onmouseover="showTip(event, '128', 301)" class="fn">b</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '138', 302)" onmouseover="showTip(event, '138', 302)" class="uc">GlobalIndex</span> <span onmouseout="hideTip(event, '127', 303)" onmouseover="showTip(event, '127', 303)" class="fn">v</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 304)" onmouseover="showTip(event, '128', 304)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 305)" onmouseover="showTip(event, '87', 305)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 306)" onmouseover="showTip(event, '88', 306)" class="id">write</span> <span onmouseout="hideTip(event, '129', 307)" onmouseover="showTip(event, '129', 307)" class="m">ParamSize</span><span class="pn">.</span><span onmouseout="hideTip(event, '123', 308)" onmouseover="showTip(event, '123', 308)" class="id">globalIndex</span> <span onmouseout="hideTip(event, '90', 309)" onmouseover="showTip(event, '90', 309)" class="fn">buffer</span> <span onmouseout="hideTip(event, '87', 310)" onmouseover="showTip(event, '87', 310)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 311)" onmouseover="showTip(event, '88', 311)" class="id">write</span> <span onmouseout="hideTip(event, '127', 312)" onmouseover="showTip(event, '127', 312)" class="fn">v</span> <span onmouseout="hideTip(event, '128', 313)" onmouseover="showTip(event, '128', 313)" class="fn">b</span> <span class="k">let</span> <span onmouseout="hideTip(event, '139', 314)" onmouseover="showTip(event, '139', 314)" class="fn">paramLength</span> <span class="o">=</span> <span class="k">function</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '126', 315)" onmouseover="showTip(event, '126', 315)" class="uc">Byte</span> <span class="id">_</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '138', 316)" onmouseover="showTip(event, '138', 316)" class="uc">GlobalIndex</span> <span class="id">_</span> <span class="k">-&gt;</span> <span class="n">2</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '131', 317)" onmouseover="showTip(event, '131', 317)" class="uc">UShort</span> <span class="id">_</span> <span class="k">-&gt;</span> <span class="n">3</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '133', 318)" onmouseover="showTip(event, '133', 318)" class="uc">UInt</span> <span class="id">_</span> <span class="k">-&gt;</span> <span class="n">5</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '136', 319)" onmouseover="showTip(event, '136', 319)" class="uc">String</span> <span onmouseout="hideTip(event, '140', 320)" onmouseover="showTip(event, '140', 320)" class="fn">l</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '106', 321)" onmouseover="showTip(event, '106', 321)" class="rt">Encoding</span><span class="pn">.</span><span onmouseout="hideTip(event, '107', 322)" onmouseover="showTip(event, '107', 322)" class="id">UTF8</span><span class="pn">.</span><span onmouseout="hideTip(event, '141', 323)" onmouseover="showTip(event, '141', 323)" class="id">GetByteCount</span> <span onmouseout="hideTip(event, '140', 324)" onmouseover="showTip(event, '140', 324)" class="fn">l</span> <span class="o">+</span> <span class="n">2</span> </code></pre> <p>So we can define a command as a union:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '142', 325)" onmouseover="showTip(event, '142', 325)" class="rt">Command</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">Direct</span> <span class="k">of</span> <span onmouseout="hideTip(event, '85', 326)" onmouseover="showTip(event, '85', 326)" class="en">Opcode</span> <span class="pn">*</span> <span onmouseout="hideTip(event, '115', 327)" onmouseover="showTip(event, '115', 327)" class="rt">Parameter</span> <span onmouseout="hideTip(event, '143', 328)" onmouseover="showTip(event, '143', 328)" class="rt">list</span> <span class="c">// we will not model SystemCommand here</span> <span class="c">// | SystemCommand of SystemOpcode * Parameter list</span> </code></pre> <p>Computing the size of a command is fairly straightforward:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '144', 329)" onmouseover="showTip(event, '144', 329)" class="fn">length</span> <span class="o">=</span> <span class="k">function</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '145', 330)" onmouseover="showTip(event, '145', 330)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '146', 331)" onmouseover="showTip(event, '146', 331)" class="fn">code</span><span class="pn">,</span> <span onmouseout="hideTip(event, '147', 332)" onmouseover="showTip(event, '147', 332)" class="fn">parameters</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '113', 333)" onmouseover="showTip(event, '113', 333)" class="fn">opcodeLength</span> <span onmouseout="hideTip(event, '146', 334)" onmouseover="showTip(event, '146', 334)" class="fn">code</span> <span class="o">+</span> <span onmouseout="hideTip(event, '148', 335)" onmouseover="showTip(event, '148', 335)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '149', 336)" onmouseover="showTip(event, '149', 336)" class="id">sumBy</span> <span onmouseout="hideTip(event, '139', 337)" onmouseover="showTip(event, '139', 337)" class="fn">paramLength</span> <span onmouseout="hideTip(event, '147', 338)" onmouseover="showTip(event, '147', 338)" class="fn">parameters</span> </code></pre> <p>The serialization is a bit more complicated if we want to loop on parameters using a recursive function. The reason is that F# doesn't currently support <code>Span&lt;T&gt; -&gt; Span&lt;T&gt;</code> function parameters. This signature is used by our serializers that take a Span, write at the beginning an returns a shorter span starting after written bytes. To workaround this problem we have to use a plain delegate:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '150', 339)" onmouseover="showTip(event, '150', 339)" class="rt">Serializer</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 340)" onmouseover="showTip(event, '151', 340)" class="id">t</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">delegate</span> <span class="k">of</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 341)" onmouseover="showTip(event, '151', 341)" class="id">t</span> <span class="pn">*</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 342)" onmouseover="showTip(event, '10', 342)" class="vt">byte</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 343)" onmouseover="showTip(event, '10', 343)" class="vt">byte</span><span class="pn">&gt;</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '152', 344)" onmouseover="showTip(event, '152', 344)" class="fn">serializeAll</span> <span class="pn">(</span><span onmouseout="hideTip(event, '153', 345)" onmouseover="showTip(event, '153', 345)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 346)" onmouseover="showTip(event, '151', 346)" class="id">t</span> <span onmouseout="hideTip(event, '150', 347)" onmouseover="showTip(event, '150', 347)" class="rt">Serializer</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '154', 348)" onmouseover="showTip(event, '154', 348)" class="fn">ps</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 349)" onmouseover="showTip(event, '151', 349)" class="id">t</span> <span onmouseout="hideTip(event, '143', 350)" onmouseover="showTip(event, '143', 350)" class="rt">list</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '128', 351)" onmouseover="showTip(event, '128', 351)" class="fn">b</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 352)" onmouseover="showTip(event, '10', 352)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '154', 353)" onmouseover="showTip(event, '154', 353)" class="fn">ps</span> <span class="k">with</span> <span class="pn">|</span> <span class="pn">[</span><span class="pn">]</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '128', 354)" onmouseover="showTip(event, '128', 354)" class="fn">b</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '155', 355)" onmouseover="showTip(event, '155', 355)" class="fn">p</span> <span class="uc">::</span> <span onmouseout="hideTip(event, '156', 356)" onmouseover="showTip(event, '156', 356)" class="fn">t</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '157', 357)" onmouseover="showTip(event, '157', 357)" class="fn">b&#39;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '153', 358)" onmouseover="showTip(event, '153', 358)" class="fn">f</span><span class="pn">.</span><span onmouseout="hideTip(event, '158', 359)" onmouseover="showTip(event, '158', 359)" class="id">Invoke</span><span class="pn">(</span><span onmouseout="hideTip(event, '155', 360)" onmouseover="showTip(event, '155', 360)" class="fn">p</span><span class="pn">,</span> <span onmouseout="hideTip(event, '128', 361)" onmouseover="showTip(event, '128', 361)" class="fn">b</span><span class="pn">)</span> <span onmouseout="hideTip(event, '152', 362)" onmouseover="showTip(event, '152', 362)" class="fn">serializeAll</span> <span onmouseout="hideTip(event, '153', 363)" onmouseover="showTip(event, '153', 363)" class="fn">f</span> <span onmouseout="hideTip(event, '156', 364)" onmouseover="showTip(event, '156', 364)" class="fn">t</span> <span onmouseout="hideTip(event, '157', 365)" onmouseover="showTip(event, '157', 365)" class="fn">b&#39;</span> </code></pre> <p>The <code>serializeAll</code> function takes a Serializer, a list of values and a buffer. It serializes all elements in the list using the serializer and returns a span that starts just after the bytes we just wrote.</p> <p>We use it to implement <code>serializeCommand</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '159', 366)" onmouseover="showTip(event, '159', 366)" class="fn">serializeCommand</span> <span onmouseout="hideTip(event, '160', 367)" onmouseover="showTip(event, '160', 367)" class="fn">command</span> <span class="pn">(</span><span onmouseout="hideTip(event, '90', 368)" onmouseover="showTip(event, '90', 368)" class="fn">buffer</span><span class="pn">:</span> <span class="vt">Span</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 369)" onmouseover="showTip(event, '10', 369)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '160', 370)" onmouseover="showTip(event, '160', 370)" class="fn">command</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '145', 371)" onmouseover="showTip(event, '145', 371)" class="uc">Direct</span> <span class="pn">(</span><span onmouseout="hideTip(event, '111', 372)" onmouseover="showTip(event, '111', 372)" class="fn">op</span><span class="pn">,</span> <span onmouseout="hideTip(event, '161', 373)" onmouseover="showTip(event, '161', 373)" class="fn">p</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 374)" onmouseover="showTip(event, '128', 374)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '110', 375)" onmouseover="showTip(event, '110', 375)" class="fn">serializeOpcode</span> <span onmouseout="hideTip(event, '111', 376)" onmouseover="showTip(event, '111', 376)" class="fn">op</span> <span onmouseout="hideTip(event, '90', 377)" onmouseover="showTip(event, '90', 377)" class="fn">buffer</span> <span onmouseout="hideTip(event, '152', 378)" onmouseover="showTip(event, '152', 378)" class="fn">serializeAll</span> <span class="pn">(</span><span onmouseout="hideTip(event, '150', 379)" onmouseover="showTip(event, '150', 379)" class="fn">Serializer</span> <span onmouseout="hideTip(event, '124', 380)" onmouseover="showTip(event, '124', 380)" class="fn">serializeParam</span><span class="pn">)</span> <span onmouseout="hideTip(event, '161', 381)" onmouseover="showTip(event, '161', 381)" class="fn">p</span> <span onmouseout="hideTip(event, '128', 382)" onmouseover="showTip(event, '128', 382)" class="fn">b</span> </code></pre> <h3><a name="Putting-it-all-together" class="anchor" href="#Putting-it-all-together">Putting it all together</a></h3> <p>We can now proceed to the <code>serialize</code> function that allocates memory from the <code>MemoryPool</code>, writes each part using the functions we defined above, and returns a memory owner. The memory owner has to be disposed to return the memory to the pool.</p> <p>It takes a command list and serialize all the commands using serializeAll:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '162', 383)" onmouseover="showTip(event, '162', 383)" class="fn">serialize</span> <span onmouseout="hideTip(event, '58', 384)" onmouseover="showTip(event, '58', 384)" class="fn">sequence</span> <span onmouseout="hideTip(event, '163', 385)" onmouseover="showTip(event, '163', 385)" class="fn">commandType</span> <span onmouseout="hideTip(event, '164', 386)" onmouseover="showTip(event, '164', 386)" class="fn">globalSize</span> <span onmouseout="hideTip(event, '165', 387)" onmouseover="showTip(event, '165', 387)" class="fn">commands</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '166', 388)" onmouseover="showTip(event, '166', 388)" class="fn">length</span> <span class="o">=</span> <span class="n">5</span> <span class="o">+</span> <span onmouseout="hideTip(event, '148', 389)" onmouseover="showTip(event, '148', 389)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '149', 390)" onmouseover="showTip(event, '149', 390)" class="id">sumBy</span> <span onmouseout="hideTip(event, '166', 391)" onmouseover="showTip(event, '166', 391)" class="fn">length</span> <span onmouseout="hideTip(event, '165', 392)" onmouseover="showTip(event, '165', 392)" class="fn">commands</span> <span class="c">// there is a 5 bytes header</span> <span class="k">let</span> <span onmouseout="hideTip(event, '167', 393)" onmouseover="showTip(event, '167', 393)" class="d">rental</span> <span class="o">=</span> <span onmouseout="hideTip(event, '168', 394)" onmouseover="showTip(event, '168', 394)" class="d">MemoryPool</span><span class="pn">.</span><span onmouseout="hideTip(event, '169', 395)" onmouseover="showTip(event, '169', 395)" class="id">Shared</span><span class="pn">.</span><span onmouseout="hideTip(event, '170', 396)" onmouseover="showTip(event, '170', 396)" class="id">Rent</span><span class="pn">(</span><span onmouseout="hideTip(event, '166', 397)" onmouseover="showTip(event, '166', 397)" class="fn">length</span><span class="o">+</span><span class="n">2</span><span class="pn">)</span> <span class="c">// plus the 2 bytes for size</span> <span class="k">let</span> <span onmouseout="hideTip(event, '171', 398)" onmouseover="showTip(event, '171', 398)" class="fn">mem</span> <span class="o">=</span> <span onmouseout="hideTip(event, '167', 399)" onmouseover="showTip(event, '167', 399)" class="d">rental</span><span class="pn">.</span><span onmouseout="hideTip(event, '172', 400)" onmouseover="showTip(event, '172', 400)" class="prop">Memory</span><span class="pn">.</span><span onmouseout="hideTip(event, '173', 401)" onmouseover="showTip(event, '173', 401)" class="id">Slice</span><span class="pn">(</span><span class="n">0</span><span class="pn">,</span><span onmouseout="hideTip(event, '166', 402)" onmouseover="showTip(event, '166', 402)" class="fn">length</span><span class="o">+</span><span class="n">2</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '90', 403)" onmouseover="showTip(event, '90', 403)" class="fn">buffer</span> <span class="o">=</span> <span onmouseout="hideTip(event, '171', 404)" onmouseover="showTip(event, '171', 404)" class="fn">mem</span><span class="pn">.</span><span onmouseout="hideTip(event, '174', 405)" onmouseover="showTip(event, '174', 405)" class="id">Span</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 406)" onmouseover="showTip(event, '128', 406)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 407)" onmouseover="showTip(event, '87', 407)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '92', 408)" onmouseover="showTip(event, '92', 408)" class="id">writeUint16</span> <span class="pn">(</span><span onmouseout="hideTip(event, '64', 409)" onmouseover="showTip(event, '64', 409)" class="fn">uint16</span> <span onmouseout="hideTip(event, '166', 410)" onmouseover="showTip(event, '166', 410)" class="fn">length</span><span class="pn">)</span> <span onmouseout="hideTip(event, '90', 411)" onmouseover="showTip(event, '90', 411)" class="fn">buffer</span> <span class="c">// 2 bytes size</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 412)" onmouseover="showTip(event, '128', 412)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 413)" onmouseover="showTip(event, '87', 413)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '92', 414)" onmouseover="showTip(event, '92', 414)" class="id">writeUint16</span> <span onmouseout="hideTip(event, '58', 415)" onmouseover="showTip(event, '58', 415)" class="fn">sequence</span> <span onmouseout="hideTip(event, '128', 416)" onmouseover="showTip(event, '128', 416)" class="fn">b</span> <span class="c">// 2 bytes sequence number</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 417)" onmouseover="showTip(event, '128', 417)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 418)" onmouseover="showTip(event, '87', 418)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '88', 419)" onmouseover="showTip(event, '88', 419)" class="id">write</span> <span onmouseout="hideTip(event, '163', 420)" onmouseover="showTip(event, '163', 420)" class="fn">commandType</span> <span onmouseout="hideTip(event, '128', 421)" onmouseover="showTip(event, '128', 421)" class="fn">b</span> <span class="c">// 1 byte command type</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 422)" onmouseover="showTip(event, '128', 422)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '87', 423)" onmouseover="showTip(event, '87', 423)" class="m">Buffer</span><span class="pn">.</span><span onmouseout="hideTip(event, '92', 424)" onmouseover="showTip(event, '92', 424)" class="id">writeUint16</span> <span onmouseout="hideTip(event, '164', 425)" onmouseover="showTip(event, '164', 425)" class="fn">globalSize</span> <span onmouseout="hideTip(event, '128', 426)" onmouseover="showTip(event, '128', 426)" class="fn">b</span> <span class="c">// 2 bytes globalSize of response</span> <span class="k">let</span> <span class="id">_</span> <span class="o">=</span> <span onmouseout="hideTip(event, '152', 427)" onmouseover="showTip(event, '152', 427)" class="fn">serializeAll</span> <span class="pn">(</span><span onmouseout="hideTip(event, '150', 428)" onmouseover="showTip(event, '150', 428)" class="fn">Serializer</span> <span onmouseout="hideTip(event, '159', 429)" onmouseover="showTip(event, '159', 429)" class="fn">serializeCommand</span><span class="pn">)</span> <span onmouseout="hideTip(event, '165', 430)" onmouseover="showTip(event, '165', 430)" class="fn">commands</span> <span onmouseout="hideTip(event, '128', 431)" onmouseover="showTip(event, '128', 431)" class="fn">b</span> <span class="c">// commands bytes</span> <span class="pn">{</span> <span class="k">new</span> <span onmouseout="hideTip(event, '175', 432)" onmouseover="showTip(event, '175', 432)" class="d">IMemoryOwner</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 433)" onmouseover="showTip(event, '10', 433)" class="vt">byte</span><span class="pn">&gt;</span> <span class="k">with</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span onmouseout="hideTip(event, '176', 434)" onmouseover="showTip(event, '176', 434)" class="fn">Memory</span> <span class="o">=</span> <span onmouseout="hideTip(event, '171', 435)" onmouseover="showTip(event, '171', 435)" class="fn">mem</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">Dispose</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '167', 436)" onmouseover="showTip(event, '167', 436)" class="d">rental</span><span class="pn">.</span><span onmouseout="hideTip(event, '177', 437)" onmouseover="showTip(event, '177', 437)" class="id">Dispose</span><span class="pn">(</span><span class="pn">)</span> <span class="pn">}</span> </code></pre> <p>And we write a <code>send</code> function that takes a list of commands, serialize them and sends the result to the brick:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '178', 438)" onmouseover="showTip(event, '178', 438)" class="fn">send</span> <span onmouseout="hideTip(event, '165', 439)" onmouseover="showTip(event, '165', 439)" class="fn">commands</span> <span class="o">=</span> <span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '179', 440)" onmouseover="showTip(event, '179', 440)" class="d">brick</span><span class="pn">:</span> <span onmouseout="hideTip(event, '34', 441)" onmouseover="showTip(event, '34', 441)" class="d">Brick</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 442)" onmouseover="showTip(event, '18', 442)" class="k">async</span> <span class="pn">{</span> <span class="c">// generates a sequence number</span> <span class="k">let</span> <span onmouseout="hideTip(event, '58', 443)" onmouseover="showTip(event, '58', 443)" class="fn">sequence</span> <span class="o">=</span> <span onmouseout="hideTip(event, '179', 444)" onmouseover="showTip(event, '179', 444)" class="d">brick</span><span class="pn">.</span><span onmouseout="hideTip(event, '180', 445)" onmouseover="showTip(event, '180', 445)" class="id">GetNextSequence</span><span class="pn">(</span><span class="pn">)</span> <span class="c">// serialize the commands in a Memory buffer</span> <span class="c">// (that will be disposed at the end of the call)</span> <span class="k">use</span> <span onmouseout="hideTip(event, '181', 446)" onmouseover="showTip(event, '181', 446)" class="d">memory</span> <span class="o">=</span> <span onmouseout="hideTip(event, '165', 447)" onmouseover="showTip(event, '165', 447)" class="fn">commands</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '162', 448)" onmouseover="showTip(event, '162', 448)" class="fn">serialize</span> <span onmouseout="hideTip(event, '58', 449)" onmouseover="showTip(event, '58', 449)" class="fn">sequence</span> <span onmouseout="hideTip(event, '182', 450)" onmouseover="showTip(event, '182', 450)" class="m">CommandType</span><span class="pn">.</span><span onmouseout="hideTip(event, '82', 451)" onmouseover="showTip(event, '82', 451)" class="id">directNoReply</span> <span class="n">0us</span> <span class="c">// send it to the brick</span> <span class="k">do!</span> <span onmouseout="hideTip(event, '179', 452)" onmouseover="showTip(event, '179', 452)" class="d">brick</span><span class="pn">.</span><span onmouseout="hideTip(event, '74', 453)" onmouseover="showTip(event, '74', 453)" class="id">AsyncWrite</span><span class="pn">(</span><span onmouseout="hideTip(event, '176', 454)" onmouseover="showTip(event, '176', 454)" class="vt">Memory</span><span class="pn">.</span><span onmouseout="hideTip(event, '183', 455)" onmouseover="showTip(event, '183', 455)" class="id">op_Implicit</span> <span onmouseout="hideTip(event, '181', 456)" onmouseover="showTip(event, '181', 456)" class="d">memory</span><span class="pn">.</span><span onmouseout="hideTip(event, '172', 457)" onmouseover="showTip(event, '172', 457)" class="id">Memory</span><span class="pn">)</span> <span class="pn">}</span> </code></pre> <h3><a name="Defining-commands" class="anchor" href="#Defining-commands">Defining commands</a></h3> <p>We're now ready to define commands in a more friendly way.</p> <p>For instance the <code>startMotor</code> command can be called with a list of output ports (the ones on the top of the brick calls A, B, C and D):</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '184', 458)" onmouseover="showTip(event, '184', 458)" class="rt">OutputPort</span> <span class="o">=</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '185', 459)" onmouseover="showTip(event, '185', 459)" class="uc">A</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '186', 460)" onmouseover="showTip(event, '186', 460)" class="uc">B</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '187', 461)" onmouseover="showTip(event, '187', 461)" class="uc">C</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '188', 462)" onmouseover="showTip(event, '188', 462)" class="uc">D</span> </code></pre> <p>Ports are encoded as a Byte parameter with bit 0 set for A, 1 for B, 2 for C, and 3 for D:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '189', 463)" onmouseover="showTip(event, '189', 463)" class="fn">port</span> <span onmouseout="hideTip(event, '190', 464)" onmouseover="showTip(event, '190', 464)" class="fn">p</span> <span class="o">=</span> <span onmouseout="hideTip(event, '190', 465)" onmouseover="showTip(event, '190', 465)" class="fn">p</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '148', 466)" onmouseover="showTip(event, '148', 466)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '191', 467)" onmouseover="showTip(event, '191', 467)" class="id">fold</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '192', 468)" onmouseover="showTip(event, '192', 468)" class="fn">v</span> <span onmouseout="hideTip(event, '193', 469)" onmouseover="showTip(event, '193', 469)" class="fn">p</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '192', 470)" onmouseover="showTip(event, '192', 470)" class="fn">v</span> <span class="o">|||</span> <span class="k">match</span> <span onmouseout="hideTip(event, '193', 471)" onmouseover="showTip(event, '193', 471)" class="fn">p</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '185', 472)" onmouseover="showTip(event, '185', 472)" class="uc">A</span> <span class="k">-&gt;</span> <span class="n">0x01uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '186', 473)" onmouseover="showTip(event, '186', 473)" class="uc">B</span> <span class="k">-&gt;</span> <span class="n">0x02uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '187', 474)" onmouseover="showTip(event, '187', 474)" class="uc">C</span> <span class="k">-&gt;</span> <span class="n">0x04uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '188', 475)" onmouseover="showTip(event, '188', 475)" class="uc">D</span> <span class="k">-&gt;</span> <span class="n">0x08uy</span><span class="pn">)</span> <span class="n">0uy</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '126', 476)" onmouseover="showTip(event, '126', 476)" class="uc">Byte</span> </code></pre> <p><code>startMotor</code> is using the <code>OutputStart</code> opcode followed by two parameters: a 0 byte , and a port byte.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '194', 477)" onmouseover="showTip(event, '194', 477)" class="fn">startMotor</span> <span onmouseout="hideTip(event, '195', 478)" onmouseover="showTip(event, '195', 478)" class="fn">ports</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 479)" onmouseover="showTip(event, '145', 479)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 480)" onmouseover="showTip(event, '85', 480)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '196', 481)" onmouseover="showTip(event, '196', 481)" class="id">OutputStart</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '126', 482)" onmouseover="showTip(event, '126', 482)" class="uc">Byte</span> <span class="n">0uy</span><span class="pn">;</span> <span onmouseout="hideTip(event, '189', 483)" onmouseover="showTip(event, '189', 483)" class="fn">port</span> <span onmouseout="hideTip(event, '195', 484)" onmouseover="showTip(event, '195', 484)" class="fn">ports</span><span class="pn">]</span><span class="pn">)</span> </code></pre> <p><code>stopMotor</code> is using the <code>OutputStop</code> opcode followed by the same parameters, and an extra Break value encoded as a 0 or 1 byte:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span class="rt">Brake</span> <span class="o">=</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '197', 485)" onmouseover="showTip(event, '197', 485)" class="uc">Brake</span> <span class="pn">|</span> <span class="uc">NoBrake</span> <span class="k">with</span> <span class="k">static</span> <span class="k">member</span> <span class="fn">toByte</span> <span onmouseout="hideTip(event, '198', 486)" onmouseover="showTip(event, '198', 486)" class="fn">b</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '198', 487)" onmouseover="showTip(event, '198', 487)" class="fn">b</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '199', 488)" onmouseover="showTip(event, '199', 488)" class="uc">Brake</span> <span class="k">-&gt;</span> <span class="n">0x01uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '200', 489)" onmouseover="showTip(event, '200', 489)" class="uc">NoBrake</span> <span class="k">-&gt;</span> <span class="n">0x00uy</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '126', 490)" onmouseover="showTip(event, '126', 490)" class="uc">Byte</span> <span class="k">let</span> <span onmouseout="hideTip(event, '201', 491)" onmouseover="showTip(event, '201', 491)" class="fn">stopMotor</span> <span onmouseout="hideTip(event, '195', 492)" onmouseover="showTip(event, '195', 492)" class="fn">ports</span> <span onmouseout="hideTip(event, '202', 493)" onmouseover="showTip(event, '202', 493)" class="fn">brake</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 494)" onmouseover="showTip(event, '145', 494)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 495)" onmouseover="showTip(event, '85', 495)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '203', 496)" onmouseover="showTip(event, '203', 496)" class="id">OutputStop</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '126', 497)" onmouseover="showTip(event, '126', 497)" class="uc">Byte</span> <span class="n">0uy</span><span class="pn">;</span> <span onmouseout="hideTip(event, '189', 498)" onmouseover="showTip(event, '189', 498)" class="fn">port</span> <span onmouseout="hideTip(event, '195', 499)" onmouseover="showTip(event, '195', 499)" class="fn">ports</span><span class="pn">;</span> <span onmouseout="hideTip(event, '199', 500)" onmouseover="showTip(event, '199', 500)" class="rt">Brake</span><span class="pn">.</span><span onmouseout="hideTip(event, '204', 501)" onmouseover="showTip(event, '204', 501)" class="id">toByte</span> <span onmouseout="hideTip(event, '202', 502)" onmouseover="showTip(event, '202', 502)" class="fn">brake</span> <span class="pn">]</span><span class="pn">)</span> </code></pre> <p>Here are a few more commands:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '205', 503)" onmouseover="showTip(event, '205', 503)" class="rt">Power</span> <span class="o">=</span> <span onmouseout="hideTip(event, '206', 504)" onmouseover="showTip(event, '206', 504)" class="uc">Power</span> <span class="k">of</span> <span onmouseout="hideTip(event, '117', 505)" onmouseover="showTip(event, '117', 505)" class="vt">uint8</span> <span class="k">let</span> <span onmouseout="hideTip(event, '207', 506)" onmouseover="showTip(event, '207', 506)" class="fn">power</span> <span onmouseout="hideTip(event, '208', 507)" onmouseover="showTip(event, '208', 507)" class="fn">p</span> <span class="o">=</span> <span class="k">if</span> <span onmouseout="hideTip(event, '208', 508)" onmouseover="showTip(event, '208', 508)" class="fn">p</span> <span class="o">&lt;</span> <span class="o">-</span><span class="n">100</span> <span class="o">||</span> <span onmouseout="hideTip(event, '208', 509)" onmouseover="showTip(event, '208', 509)" class="fn">p</span> <span class="o">&gt;</span> <span class="n">100</span> <span class="k">then</span> <span onmouseout="hideTip(event, '209', 510)" onmouseover="showTip(event, '209', 510)" class="fn">invalidArg</span> <span class="s">&quot;p&quot;</span> <span class="s">&quot;Power should be between -100 and 100&quot;</span> <span onmouseout="hideTip(event, '205', 511)" onmouseover="showTip(event, '205', 511)" class="uc">Power</span> <span class="pn">(</span><span onmouseout="hideTip(event, '117', 512)" onmouseover="showTip(event, '117', 512)" class="fn">uint8</span> <span onmouseout="hideTip(event, '208', 513)" onmouseover="showTip(event, '208', 513)" class="fn">p</span><span class="pn">)</span> <span class="c">/// wait for the end of previous command</span> <span class="k">let</span> <span onmouseout="hideTip(event, '210', 514)" onmouseover="showTip(event, '210', 514)" class="fn">outputReady</span> <span onmouseout="hideTip(event, '195', 515)" onmouseover="showTip(event, '195', 515)" class="fn">ports</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 516)" onmouseover="showTip(event, '145', 516)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 517)" onmouseover="showTip(event, '85', 517)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '211', 518)" onmouseover="showTip(event, '211', 518)" class="id">OutputReady</span><span class="pn">,</span> <span class="pn">[</span> <span onmouseout="hideTip(event, '126', 519)" onmouseover="showTip(event, '126', 519)" class="uc">Byte</span> <span class="n">0uy</span><span class="pn">;</span> <span onmouseout="hideTip(event, '189', 520)" onmouseover="showTip(event, '189', 520)" class="fn">port</span> <span onmouseout="hideTip(event, '195', 521)" onmouseover="showTip(event, '195', 521)" class="fn">ports</span><span class="pn">;</span><span class="pn">]</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '212', 522)" onmouseover="showTip(event, '212', 522)" class="fn">turnMotorAtPower</span> <span onmouseout="hideTip(event, '195', 523)" onmouseover="showTip(event, '195', 523)" class="fn">ports</span> <span class="pn">(</span><span onmouseout="hideTip(event, '205', 524)" onmouseover="showTip(event, '205', 524)" class="id">Power</span> <span onmouseout="hideTip(event, '213', 525)" onmouseover="showTip(event, '213', 525)" class="fn">power</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 526)" onmouseover="showTip(event, '145', 526)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 527)" onmouseover="showTip(event, '85', 527)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '214', 528)" onmouseover="showTip(event, '214', 528)" class="id">OutputPower</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '126', 529)" onmouseover="showTip(event, '126', 529)" class="uc">Byte</span> <span class="n">0uy</span><span class="pn">;</span> <span onmouseout="hideTip(event, '189', 530)" onmouseover="showTip(event, '189', 530)" class="fn">port</span> <span onmouseout="hideTip(event, '195', 531)" onmouseover="showTip(event, '195', 531)" class="fn">ports</span><span class="pn">;</span> <span onmouseout="hideTip(event, '126', 532)" onmouseover="showTip(event, '126', 532)" class="uc">Byte</span> <span onmouseout="hideTip(event, '207', 533)" onmouseover="showTip(event, '207', 533)" class="fn">power</span><span class="pn">]</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '215', 534)" onmouseover="showTip(event, '215', 534)" class="fn">turnMotorAtSpeedForTime&#39;</span> <span onmouseout="hideTip(event, '195', 535)" onmouseover="showTip(event, '195', 535)" class="fn">ports</span> <span onmouseout="hideTip(event, '216', 536)" onmouseover="showTip(event, '216', 536)" class="fn">speed</span> <span onmouseout="hideTip(event, '217', 537)" onmouseover="showTip(event, '217', 537)" class="fn">msRampUp</span> <span onmouseout="hideTip(event, '218', 538)" onmouseover="showTip(event, '218', 538)" class="fn">msConstant</span> <span onmouseout="hideTip(event, '219', 539)" onmouseover="showTip(event, '219', 539)" class="fn">msRampDown</span> <span onmouseout="hideTip(event, '202', 540)" onmouseover="showTip(event, '202', 540)" class="fn">brake</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 541)" onmouseover="showTip(event, '145', 541)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 542)" onmouseover="showTip(event, '85', 542)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '220', 543)" onmouseover="showTip(event, '220', 543)" class="id">OutputTimeSpeed</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '126', 544)" onmouseover="showTip(event, '126', 544)" class="uc">Byte</span> <span class="n">0uy</span> <span onmouseout="hideTip(event, '189', 545)" onmouseover="showTip(event, '189', 545)" class="fn">port</span> <span onmouseout="hideTip(event, '195', 546)" onmouseover="showTip(event, '195', 546)" class="fn">ports</span> <span onmouseout="hideTip(event, '126', 547)" onmouseover="showTip(event, '126', 547)" class="uc">Byte</span> <span class="pn">(</span><span onmouseout="hideTip(event, '10', 548)" onmouseover="showTip(event, '10', 548)" class="fn">byte</span> <span onmouseout="hideTip(event, '216', 549)" onmouseover="showTip(event, '216', 549)" class="fn">speed</span><span class="pn">)</span> <span onmouseout="hideTip(event, '133', 550)" onmouseover="showTip(event, '133', 550)" class="uc">UInt</span> <span onmouseout="hideTip(event, '217', 551)" onmouseover="showTip(event, '217', 551)" class="fn">msRampUp</span> <span onmouseout="hideTip(event, '133', 552)" onmouseover="showTip(event, '133', 552)" class="uc">UInt</span> <span onmouseout="hideTip(event, '218', 553)" onmouseover="showTip(event, '218', 553)" class="fn">msConstant</span> <span onmouseout="hideTip(event, '133', 554)" onmouseover="showTip(event, '133', 554)" class="uc">UInt</span> <span onmouseout="hideTip(event, '219', 555)" onmouseover="showTip(event, '219', 555)" class="fn">msRampDown</span> <span onmouseout="hideTip(event, '199', 556)" onmouseover="showTip(event, '199', 556)" class="rt">Brake</span><span class="pn">.</span><span onmouseout="hideTip(event, '204', 557)" onmouseover="showTip(event, '204', 557)" class="id">toByte</span> <span onmouseout="hideTip(event, '202', 558)" onmouseover="showTip(event, '202', 558)" class="fn">brake</span><span class="pn">]</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '221', 559)" onmouseover="showTip(event, '221', 559)" class="fn">turnMotorAtSpeedForTime</span> <span onmouseout="hideTip(event, '195', 560)" onmouseover="showTip(event, '195', 560)" class="fn">ports</span> <span onmouseout="hideTip(event, '216', 561)" onmouseover="showTip(event, '216', 561)" class="fn">speed</span> <span onmouseout="hideTip(event, '222', 562)" onmouseover="showTip(event, '222', 562)" class="fn">msDuration</span> <span onmouseout="hideTip(event, '202', 563)" onmouseover="showTip(event, '202', 563)" class="fn">brake</span> <span class="o">=</span> <span onmouseout="hideTip(event, '215', 564)" onmouseover="showTip(event, '215', 564)" class="fn">turnMotorAtSpeedForTime&#39;</span> <span onmouseout="hideTip(event, '195', 565)" onmouseover="showTip(event, '195', 565)" class="fn">ports</span> <span onmouseout="hideTip(event, '216', 566)" onmouseover="showTip(event, '216', 566)" class="fn">speed</span> <span class="n">0u</span> <span onmouseout="hideTip(event, '222', 567)" onmouseover="showTip(event, '222', 567)" class="fn">msDuration</span> <span class="n">0u</span> <span onmouseout="hideTip(event, '202', 568)" onmouseover="showTip(event, '202', 568)" class="fn">brake</span> <span class="c">// yes, you can also play music :)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '223', 569)" onmouseover="showTip(event, '223', 569)" class="fn">playTone</span> <span onmouseout="hideTip(event, '224', 570)" onmouseover="showTip(event, '224', 570)" class="fn">volume</span> <span onmouseout="hideTip(event, '225', 571)" onmouseover="showTip(event, '225', 571)" class="fn">frequency</span> <span onmouseout="hideTip(event, '226', 572)" onmouseover="showTip(event, '226', 572)" class="fn">duration</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 573)" onmouseover="showTip(event, '145', 573)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '85', 574)" onmouseover="showTip(event, '85', 574)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '227', 575)" onmouseover="showTip(event, '227', 575)" class="id">Sound_Tone</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '126', 576)" onmouseover="showTip(event, '126', 576)" class="uc">Byte</span> <span onmouseout="hideTip(event, '224', 577)" onmouseover="showTip(event, '224', 577)" class="fn">volume</span> <span onmouseout="hideTip(event, '131', 578)" onmouseover="showTip(event, '131', 578)" class="uc">UShort</span> <span onmouseout="hideTip(event, '225', 579)" onmouseover="showTip(event, '225', 579)" class="fn">frequency</span> <span onmouseout="hideTip(event, '131', 580)" onmouseover="showTip(event, '131', 580)" class="uc">UShort</span> <span onmouseout="hideTip(event, '226', 581)" onmouseover="showTip(event, '226', 581)" class="fn">duration</span> <span class="pn">]</span><span class="pn">)</span> </code></pre> <p>You can try to put a few commands in the list and <code>send</code> them to the brick. It should work.</p> <h2><a name="Computation-Expression" class="anchor" href="#Computation-Expression">Computation Expression</a></h2> <p>To make it better, we continue with a <code>lego</code> computation expression that builds a full program taking commands and async local computations.</p> <p>It is used to compose functions that takes a Brick and return an async:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '228', 582)" onmouseover="showTip(event, '228', 582)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 583)" onmouseover="showTip(event, '229', 583)" class="id">a</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '34', 584)" onmouseover="showTip(event, '34', 584)" class="d">Brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '70', 585)" onmouseover="showTip(event, '70', 585)" class="rt">Async</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 586)" onmouseover="showTip(event, '229', 586)" class="id">a</span><span class="pn">&gt;</span> </code></pre> <p>This is a classic Computation expression (not an applicative).</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '230', 587)" onmouseover="showTip(event, '230', 587)" class="rt">LegoBuilder</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> </code></pre> <p>The Bind method takes a <code>Lego&lt;'a&gt;</code> and a function that takes a <code>'a</code> as an input to return a <code>Lego&lt;'b&gt;</code>. The result should be a <code>Lego&lt;'b&gt;</code>, so we write a lambda that takes a Brick.</p> <p>We pass this brick to x, to get an <code>Async&lt;'a&gt;</code>, we pass the value from this async to f using <code>async.Bind</code>.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">member</span> <span class="id">__</span><span class="pn">.</span><span class="fn">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '231', 588)" onmouseover="showTip(event, '231', 588)" class="fn">x</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 589)" onmouseover="showTip(event, '228', 589)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 590)" onmouseover="showTip(event, '229', 590)" class="id">a</span><span class="pn">&gt;</span><span class="pn">,</span> <span onmouseout="hideTip(event, '232', 591)" onmouseover="showTip(event, '232', 591)" class="fn">f</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 592)" onmouseover="showTip(event, '229', 592)" class="id">a</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '228', 593)" onmouseover="showTip(event, '228', 593)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 594)" onmouseover="showTip(event, '233', 594)" class="id">b</span><span class="pn">&gt;</span> <span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 595)" onmouseover="showTip(event, '228', 595)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 596)" onmouseover="showTip(event, '233', 596)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '179', 597)" onmouseover="showTip(event, '179', 597)" class="d">brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 598)" onmouseover="showTip(event, '18', 598)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '234', 599)" onmouseover="showTip(event, '234', 599)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '231', 600)" onmouseover="showTip(event, '231', 600)" class="fn">x</span> <span onmouseout="hideTip(event, '179', 601)" onmouseover="showTip(event, '179', 601)" class="d">brick</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '235', 602)" onmouseover="showTip(event, '235', 602)" class="fn">v</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '232', 603)" onmouseover="showTip(event, '232', 603)" class="fn">f</span> <span onmouseout="hideTip(event, '235', 604)" onmouseover="showTip(event, '235', 604)" class="fn">v</span> <span onmouseout="hideTip(event, '179', 605)" onmouseover="showTip(event, '179', 605)" class="d">brick</span><span class="pn">)</span> </code></pre> <p>This overload does quite the same but directly takes a Command list and send it</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 606)" onmouseover="showTip(event, '236', 606)" class="id">__</span><span class="pn">.</span><span class="fn">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '237', 607)" onmouseover="showTip(event, '237', 607)" class="fn">command</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '142', 608)" onmouseover="showTip(event, '142', 608)" class="rt">Command</span> <span onmouseout="hideTip(event, '143', 609)" onmouseover="showTip(event, '143', 609)" class="rt">list</span><span class="pn">,</span> <span onmouseout="hideTip(event, '238', 610)" onmouseover="showTip(event, '238', 610)" class="fn">f</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '11', 611)" onmouseover="showTip(event, '11', 611)" class="rt">unit</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '228', 612)" onmouseover="showTip(event, '228', 612)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 613)" onmouseover="showTip(event, '233', 613)" class="id">b</span><span class="pn">&gt;</span> <span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 614)" onmouseover="showTip(event, '228', 614)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 615)" onmouseover="showTip(event, '233', 615)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '179', 616)" onmouseover="showTip(event, '179', 616)" class="d">brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 617)" onmouseover="showTip(event, '18', 617)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '234', 618)" onmouseover="showTip(event, '234', 618)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '178', 619)" onmouseover="showTip(event, '178', 619)" class="fn">send</span> <span onmouseout="hideTip(event, '237', 620)" onmouseover="showTip(event, '237', 620)" class="fn">command</span> <span onmouseout="hideTip(event, '179', 621)" onmouseover="showTip(event, '179', 621)" class="d">brick</span><span class="pn">,</span> <span class="k">fun</span> <span class="pn">(</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '238', 622)" onmouseover="showTip(event, '238', 622)" class="fn">f</span> <span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '179', 623)" onmouseover="showTip(event, '179', 623)" class="d">brick</span><span class="pn">)</span> </code></pre> <p>Same thing for a single command</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 624)" onmouseover="showTip(event, '236', 624)" class="id">__</span><span class="pn">.</span><span class="fn">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '160', 625)" onmouseover="showTip(event, '160', 625)" class="fn">command</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '142', 626)" onmouseover="showTip(event, '142', 626)" class="rt">Command</span><span class="pn">,</span> <span onmouseout="hideTip(event, '238', 627)" onmouseover="showTip(event, '238', 627)" class="fn">f</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '11', 628)" onmouseover="showTip(event, '11', 628)" class="rt">unit</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '228', 629)" onmouseover="showTip(event, '228', 629)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 630)" onmouseover="showTip(event, '233', 630)" class="id">b</span><span class="pn">&gt;</span> <span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 631)" onmouseover="showTip(event, '228', 631)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 632)" onmouseover="showTip(event, '233', 632)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '179', 633)" onmouseover="showTip(event, '179', 633)" class="d">brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 634)" onmouseover="showTip(event, '18', 634)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '234', 635)" onmouseover="showTip(event, '234', 635)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '178', 636)" onmouseover="showTip(event, '178', 636)" class="fn">send</span> <span class="pn">[</span><span onmouseout="hideTip(event, '160', 637)" onmouseover="showTip(event, '160', 637)" class="fn">command</span><span class="pn">]</span> <span onmouseout="hideTip(event, '179', 638)" onmouseover="showTip(event, '179', 638)" class="d">brick</span><span class="pn">,</span> <span class="k">fun</span> <span class="pn">(</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '238', 639)" onmouseover="showTip(event, '238', 639)" class="fn">f</span> <span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '179', 640)" onmouseover="showTip(event, '179', 640)" class="d">brick</span><span class="pn">)</span> </code></pre> <p>We can also do it for simple <code>Async&lt;'a&gt;</code> (for instance <code>Async.Sleep(1000)</code>). In this case we just bind it directly.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 641)" onmouseover="showTip(event, '236', 641)" class="id">__</span><span class="pn">.</span><span class="fn">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '239', 642)" onmouseover="showTip(event, '239', 642)" class="fn">x</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '70', 643)" onmouseover="showTip(event, '70', 643)" class="rt">Async</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 644)" onmouseover="showTip(event, '229', 644)" class="id">a</span><span class="pn">&gt;</span><span class="pn">,</span> <span onmouseout="hideTip(event, '232', 645)" onmouseover="showTip(event, '232', 645)" class="fn">f</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 646)" onmouseover="showTip(event, '229', 646)" class="id">a</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '228', 647)" onmouseover="showTip(event, '228', 647)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 648)" onmouseover="showTip(event, '233', 648)" class="id">b</span><span class="pn">&gt;</span> <span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 649)" onmouseover="showTip(event, '228', 649)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 650)" onmouseover="showTip(event, '233', 650)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '179', 651)" onmouseover="showTip(event, '179', 651)" class="d">brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 652)" onmouseover="showTip(event, '18', 652)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '234', 653)" onmouseover="showTip(event, '234', 653)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '239', 654)" onmouseover="showTip(event, '239', 654)" class="fn">x</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '235', 655)" onmouseover="showTip(event, '235', 655)" class="fn">v</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '232', 656)" onmouseover="showTip(event, '232', 656)" class="fn">f</span> <span onmouseout="hideTip(event, '235', 657)" onmouseover="showTip(event, '235', 657)" class="fn">v</span> <span onmouseout="hideTip(event, '179', 658)" onmouseover="showTip(event, '179', 658)" class="d">brick</span><span class="pn">)</span> </code></pre> <p><code>Return</code> creates a <code>Lego&lt;'a&gt;</code> from a value. It just takes a brick that it will not use and returns an Async with the value.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 659)" onmouseover="showTip(event, '236', 659)" class="id">__</span><span class="pn">.</span><span class="fn">Return</span> <span onmouseout="hideTip(event, '240', 660)" onmouseover="showTip(event, '240', 660)" class="fn">x</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 661)" onmouseover="showTip(event, '228', 661)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 662)" onmouseover="showTip(event, '229', 662)" class="id">a</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">fun</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 663)" onmouseover="showTip(event, '18', 663)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '69', 664)" onmouseover="showTip(event, '69', 664)" class="id">Return</span> <span onmouseout="hideTip(event, '240', 665)" onmouseover="showTip(event, '240', 665)" class="fn">x</span> </code></pre> <p>Other methods implement return!, for, combination sequenced calls, etc.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="c">// needed for return!</span> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 666)" onmouseover="showTip(event, '236', 666)" class="id">__</span><span class="pn">.</span><span class="fn">ReturnFrom</span> <span onmouseout="hideTip(event, '241', 667)" onmouseover="showTip(event, '241', 667)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '241', 668)" onmouseover="showTip(event, '241', 668)" class="fn">x</span> <span class="c">// needed for for .. in .. do expressions</span> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 669)" onmouseover="showTip(event, '236', 669)" class="id">__</span><span class="pn">.</span><span class="fn">For</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '242', 670)" onmouseover="showTip(event, '242', 670)" class="id">T</span><span class="pn">&gt;</span><span class="pn">(</span><span onmouseout="hideTip(event, '243', 671)" onmouseover="showTip(event, '243', 671)" class="fn">values</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '242', 672)" onmouseover="showTip(event, '242', 672)" class="id">T</span> <span onmouseout="hideTip(event, '244', 673)" onmouseover="showTip(event, '244', 673)" class="if">seq</span><span class="pn">,</span> <span onmouseout="hideTip(event, '245', 674)" onmouseover="showTip(event, '245', 674)" class="fn">body</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '242', 675)" onmouseover="showTip(event, '242', 675)" class="id">T</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '228', 676)" onmouseover="showTip(event, '228', 676)" class="fn">Lego</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '11', 677)" onmouseover="showTip(event, '11', 677)" class="rt">unit</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '179', 678)" onmouseover="showTip(event, '179', 678)" class="d">brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 679)" onmouseover="showTip(event, '18', 679)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '246', 680)" onmouseover="showTip(event, '246', 680)" class="id">For</span><span class="pn">(</span><span onmouseout="hideTip(event, '243', 681)" onmouseover="showTip(event, '243', 681)" class="fn">values</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '247', 682)" onmouseover="showTip(event, '247', 682)" class="fn">t</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '245', 683)" onmouseover="showTip(event, '245', 683)" class="fn">body</span> <span onmouseout="hideTip(event, '247', 684)" onmouseover="showTip(event, '247', 684)" class="fn">t</span> <span onmouseout="hideTip(event, '179', 685)" onmouseover="showTip(event, '179', 685)" class="d">brick</span><span class="pn">)</span> <span class="c">// needed to have several do! combined</span> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 686)" onmouseover="showTip(event, '236', 686)" class="id">__</span><span class="pn">.</span><span class="fn">Combine</span><span class="pn">(</span><span onmouseout="hideTip(event, '248', 687)" onmouseover="showTip(event, '248', 687)" class="fn">x</span><span class="pn">,</span> <span onmouseout="hideTip(event, '249', 688)" onmouseover="showTip(event, '249', 688)" class="fn">y</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '228', 689)" onmouseover="showTip(event, '228', 689)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 690)" onmouseover="showTip(event, '229', 690)" class="id">a</span><span class="pn">&gt;</span><span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '250', 691)" onmouseover="showTip(event, '250', 691)" class="d">ctx</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 692)" onmouseover="showTip(event, '18', 692)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '251', 693)" onmouseover="showTip(event, '251', 693)" class="id">Combine</span><span class="pn">(</span><span onmouseout="hideTip(event, '248', 694)" onmouseover="showTip(event, '248', 694)" class="fn">x</span> <span onmouseout="hideTip(event, '250', 695)" onmouseover="showTip(event, '250', 695)" class="d">ctx</span><span class="pn">,</span> <span onmouseout="hideTip(event, '249', 696)" onmouseover="showTip(event, '249', 696)" class="fn">y</span> <span onmouseout="hideTip(event, '250', 697)" onmouseover="showTip(event, '250', 697)" class="d">ctx</span><span class="pn">)</span> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 698)" onmouseover="showTip(event, '236', 698)" class="id">__</span><span class="pn">.</span><span class="fn">Delay</span><span class="pn">(</span><span onmouseout="hideTip(event, '252', 699)" onmouseover="showTip(event, '252', 699)" class="fn">f</span><span class="pn">:</span> <span onmouseout="hideTip(event, '11', 700)" onmouseover="showTip(event, '11', 700)" class="rt">unit</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '228', 701)" onmouseover="showTip(event, '228', 701)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 702)" onmouseover="showTip(event, '229', 702)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '250', 703)" onmouseover="showTip(event, '250', 703)" class="d">ctx</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 704)" onmouseover="showTip(event, '18', 704)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '253', 705)" onmouseover="showTip(event, '253', 705)" class="id">Delay</span><span class="pn">(</span><span class="k">fun</span> <span class="pn">(</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '252', 706)" onmouseover="showTip(event, '252', 706)" class="fn">f</span> <span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '250', 707)" onmouseover="showTip(event, '250', 707)" class="d">ctx</span><span class="pn">)</span> <span class="c">// needed for if without else</span> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 708)" onmouseover="showTip(event, '236', 708)" class="id">__</span><span class="pn">.</span><span class="fn">Zero</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '254', 709)" onmouseover="showTip(event, '254', 709)" class="fn">ctx</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 710)" onmouseover="showTip(event, '18', 710)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '255', 711)" onmouseover="showTip(event, '255', 711)" class="id">Zero</span><span class="pn">(</span><span class="pn">)</span> <span class="c">// needed for use</span> <span class="k">member</span> <span onmouseout="hideTip(event, '236', 712)" onmouseover="showTip(event, '236', 712)" class="id">__</span><span class="pn">.</span><span class="fn">Using</span><span class="pn">(</span><span onmouseout="hideTip(event, '256', 713)" onmouseover="showTip(event, '256', 713)" class="d">d</span><span class="pn">,</span> <span onmouseout="hideTip(event, '257', 714)" onmouseover="showTip(event, '257', 714)" class="fn">f</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '258', 715)" onmouseover="showTip(event, '258', 715)" class="fn">ctx</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 716)" onmouseover="showTip(event, '18', 716)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '259', 717)" onmouseover="showTip(event, '259', 717)" class="id">Using</span><span class="pn">(</span><span onmouseout="hideTip(event, '256', 718)" onmouseover="showTip(event, '256', 718)" class="d">d</span><span class="pn">,</span> <span onmouseout="hideTip(event, '257', 719)" onmouseover="showTip(event, '257', 719)" class="fn">f</span> <span onmouseout="hideTip(event, '258', 720)" onmouseover="showTip(event, '258', 720)" class="fn">ctx</span><span class="pn">)</span> </code></pre> <p>The <code>run</code> functions takes a Lego<unit> function, starts it asynchronously and returns a cancellation token to stop it.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '260', 721)" onmouseover="showTip(event, '260', 721)" class="fn">run</span> <span onmouseout="hideTip(event, '179', 722)" onmouseover="showTip(event, '179', 722)" class="d">brick</span> <span class="pn">(</span><span onmouseout="hideTip(event, '261', 723)" onmouseover="showTip(event, '261', 723)" class="fn">f</span><span class="pn">:</span> <span onmouseout="hideTip(event, '228', 724)" onmouseover="showTip(event, '228', 724)" class="fn">Lego</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '11', 725)" onmouseover="showTip(event, '11', 725)" class="rt">unit</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '262', 726)" onmouseover="showTip(event, '262', 726)" class="d">cancelToken</span> <span class="o">=</span> <span class="k">new</span> <span onmouseout="hideTip(event, '263', 727)" onmouseover="showTip(event, '263', 727)" class="d">CancellationTokenSource</span><span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '70', 728)" onmouseover="showTip(event, '70', 728)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '264', 729)" onmouseover="showTip(event, '264', 729)" class="id">Start</span><span class="pn">(</span><span onmouseout="hideTip(event, '261', 730)" onmouseover="showTip(event, '261', 730)" class="fn">f</span> <span onmouseout="hideTip(event, '179', 731)" onmouseover="showTip(event, '179', 731)" class="d">brick</span><span class="pn">,</span> <span onmouseout="hideTip(event, '262', 732)" onmouseover="showTip(event, '262', 732)" class="d">cancelToken</span><span class="pn">.</span><span onmouseout="hideTip(event, '265', 733)" onmouseover="showTip(event, '265', 733)" class="id">Token</span><span class="pn">)</span> <span onmouseout="hideTip(event, '262', 734)" onmouseover="showTip(event, '262', 734)" class="d">cancelToken</span> </code></pre> <p>The <code>runSynchronously</code> functions takes a Lego<'a> function, and runs it synchronously</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '266', 735)" onmouseover="showTip(event, '266', 735)" class="fn">runSynchronously</span> <span onmouseout="hideTip(event, '179', 736)" onmouseover="showTip(event, '179', 736)" class="d">brick</span> <span class="pn">(</span><span onmouseout="hideTip(event, '267', 737)" onmouseover="showTip(event, '267', 737)" class="fn">f</span><span class="pn">:</span> <span onmouseout="hideTip(event, '228', 738)" onmouseover="showTip(event, '228', 738)" class="fn">Lego</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 739)" onmouseover="showTip(event, '229', 739)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '70', 740)" onmouseover="showTip(event, '70', 740)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '268', 741)" onmouseover="showTip(event, '268', 741)" class="id">RunSynchronously</span><span class="pn">(</span><span onmouseout="hideTip(event, '267', 742)" onmouseover="showTip(event, '267', 742)" class="fn">f</span> <span onmouseout="hideTip(event, '179', 743)" onmouseover="showTip(event, '179', 743)" class="d">brick</span><span class="pn">)</span> </code></pre> <p>We choose <code>lego</code> for our Computation Expression name</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '269', 744)" onmouseover="showTip(event, '269', 744)" class="id">lego</span> <span class="o">=</span> <span onmouseout="hideTip(event, '230', 745)" onmouseover="showTip(event, '230', 745)" class="fn">LegoBuilder</span><span class="pn">(</span><span class="pn">)</span> </code></pre> <h2><a name="Let-s-play" class="anchor" href="#Let-s-play">Let's play</a></h2> <p>Here is a sample that connects to COM9 and repeat 3 times a batch of commands to turn motor in port A in one direction for 1 second, then in the other direction for another second. It stops motors once done.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '270', 746)" onmouseover="showTip(event, '270', 746)" class="fn">sample</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="k">use</span> <span onmouseout="hideTip(event, '179', 747)" onmouseover="showTip(event, '179', 747)" class="d">brick</span> <span class="o">=</span> <span class="k">new</span> <span onmouseout="hideTip(event, '34', 748)" onmouseover="showTip(event, '34', 748)" class="d">Brick</span><span class="pn">(</span><span class="s">&quot;COM9&quot;</span><span class="pn">)</span> <span onmouseout="hideTip(event, '179', 749)" onmouseover="showTip(event, '179', 749)" class="d">brick</span><span class="pn">.</span><span onmouseout="hideTip(event, '271', 750)" onmouseover="showTip(event, '271', 750)" class="id">Connect</span><span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '269', 751)" onmouseover="showTip(event, '269', 751)" class="k">lego</span> <span class="pn">{</span> <span class="k">for</span> <span onmouseout="hideTip(event, '272', 752)" onmouseover="showTip(event, '272', 752)" class="fn">i</span> <span class="k">in</span> <span class="n">0..</span><span class="n">3</span> <span class="k">do</span> <span class="k">do!</span> <span class="pn">[</span> <span onmouseout="hideTip(event, '221', 753)" onmouseover="showTip(event, '221', 753)" class="fn">turnMotorAtSpeedForTime</span> <span class="pn">[</span><span onmouseout="hideTip(event, '185', 754)" onmouseover="showTip(event, '185', 754)" class="uc">A</span><span class="pn">]</span> <span class="n">50</span> <span class="n">1000u</span> <span onmouseout="hideTip(event, '200', 755)" onmouseover="showTip(event, '200', 755)" class="uc">NoBrake</span> <span onmouseout="hideTip(event, '210', 756)" onmouseover="showTip(event, '210', 756)" class="fn">outputReady</span> <span class="pn">[</span><span onmouseout="hideTip(event, '185', 757)" onmouseover="showTip(event, '185', 757)" class="uc">A</span><span class="pn">]</span> <span onmouseout="hideTip(event, '221', 758)" onmouseover="showTip(event, '221', 758)" class="fn">turnMotorAtSpeedForTime</span> <span class="pn">[</span><span onmouseout="hideTip(event, '185', 759)" onmouseover="showTip(event, '185', 759)" class="uc">A</span><span class="pn">]</span> <span class="o">-</span><span class="n">50</span> <span class="n">1000u</span> <span onmouseout="hideTip(event, '200', 760)" onmouseover="showTip(event, '200', 760)" class="uc">NoBrake</span> <span onmouseout="hideTip(event, '210', 761)" onmouseover="showTip(event, '210', 761)" class="fn">outputReady</span> <span class="pn">[</span><span onmouseout="hideTip(event, '185', 762)" onmouseover="showTip(event, '185', 762)" class="uc">A</span><span class="pn">]</span> <span class="pn">]</span> <span class="k">do!</span> <span onmouseout="hideTip(event, '201', 763)" onmouseover="showTip(event, '201', 763)" class="fn">stopMotor</span> <span class="pn">[</span><span onmouseout="hideTip(event, '185', 764)" onmouseover="showTip(event, '185', 764)" class="uc">A</span><span class="pn">]</span> <span onmouseout="hideTip(event, '200', 765)" onmouseover="showTip(event, '200', 765)" class="uc">NoBrake</span> <span class="pn">}</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '266', 766)" onmouseover="showTip(event, '266', 766)" class="fn">runSynchronously</span> <span onmouseout="hideTip(event, '179', 767)" onmouseover="showTip(event, '179', 767)" class="d">brick</span> </code></pre> <h2><a name="Sensors" class="anchor" href="#Sensors">Sensors</a></h2> <p>The Ev3 comes with 3 default sensors, Color, Touch and IR. Extra gyroscopic and ultrasound sensors can be acquired separately.</p> <p>Sensors are connected to input ports (1 to 4). Motor ports (A to D) can also be read to get the rotation of the motors:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '273', 768)" onmouseover="showTip(event, '273', 768)" class="rt">InputPort</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">In1</span> <span class="pn">|</span> <span class="uc">In2</span> <span class="pn">|</span> <span class="uc">In3</span> <span class="pn">|</span> <span class="uc">In4</span> <span class="pn">|</span> <span class="uc">InA</span> <span class="pn">|</span> <span class="uc">InB</span> <span class="pn">|</span> <span class="uc">InC</span> <span class="pn">|</span> <span class="uc">InD</span> <span class="c">/// gets the binary code for an input port</span> <span class="k">let</span> <span onmouseout="hideTip(event, '274', 769)" onmouseover="showTip(event, '274', 769)" class="fn">inputPort</span> <span class="o">=</span> <span class="k">function</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '275', 770)" onmouseover="showTip(event, '275', 770)" class="uc">In1</span> <span class="k">-&gt;</span> <span class="n">0x00uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '276', 771)" onmouseover="showTip(event, '276', 771)" class="uc">In2</span> <span class="k">-&gt;</span> <span class="n">0x01uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '277', 772)" onmouseover="showTip(event, '277', 772)" class="uc">In3</span> <span class="k">-&gt;</span> <span class="n">0x02uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '278', 773)" onmouseover="showTip(event, '278', 773)" class="uc">In4</span> <span class="k">-&gt;</span> <span class="n">0x03uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '279', 774)" onmouseover="showTip(event, '279', 774)" class="uc">InA</span> <span class="k">-&gt;</span> <span class="n">0x10uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '280', 775)" onmouseover="showTip(event, '280', 775)" class="uc">InB</span> <span class="k">-&gt;</span> <span class="n">0x11uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '281', 776)" onmouseover="showTip(event, '281', 776)" class="uc">InC</span> <span class="k">-&gt;</span> <span class="n">0x12uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '282', 777)" onmouseover="showTip(event, '282', 777)" class="uc">InD</span> <span class="k">-&gt;</span> <span class="n">0x13uy</span> <span class="o">&gt;</span><span class="pn">&gt;</span> <span onmouseout="hideTip(event, '126', 778)" onmouseover="showTip(event, '126', 778)" class="uc">Byte</span> </code></pre> <p>Sensors can return different values</p> <ul> <li>Color, ambient light, reflected light for the color sensor</li> <li>Touch can return pressed/released state or bumps</li> <li>IR can return proximity, and remote buttons state...</li> </ul> <p>each of this mode correspond to a 1 byte value</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '283', 779)" onmouseover="showTip(event, '283', 779)" class="rt">Mode</span> <span class="o">=</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '284', 780)" onmouseover="showTip(event, '284', 780)" class="uc">TouchMode</span> <span class="k">of</span> <span onmouseout="hideTip(event, '284', 781)" onmouseover="showTip(event, '284', 781)" class="rt">TouchMode</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '285', 782)" onmouseover="showTip(event, '285', 782)" class="uc">ColorMode</span> <span class="k">of</span> <span onmouseout="hideTip(event, '285', 783)" onmouseover="showTip(event, '285', 783)" class="rt">ColorMode</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '286', 784)" onmouseover="showTip(event, '286', 784)" class="uc">IRMode</span> <span class="k">of</span> <span onmouseout="hideTip(event, '286', 785)" onmouseover="showTip(event, '286', 785)" class="rt">IRMode</span> <span class="k">and</span> <span onmouseout="hideTip(event, '284', 786)" onmouseover="showTip(event, '284', 786)" class="rt">TouchMode</span> <span class="o">=</span> <span class="uc">Touch</span> <span class="pn">|</span> <span class="uc">Bumps</span> <span class="k">and</span> <span onmouseout="hideTip(event, '285', 787)" onmouseover="showTip(event, '285', 787)" class="rt">ColorMode</span> <span class="o">=</span> <span class="uc">Reflective</span> <span class="pn">|</span> <span class="uc">Ambient</span> <span class="pn">|</span> <span class="uc">Color</span> <span class="pn">|</span> <span class="uc">ReflectiveRaw</span> <span class="pn">|</span> <span class="uc">ReflectiveRgb</span> <span class="pn">|</span> <span class="uc">Calibration</span> <span class="k">and</span> <span onmouseout="hideTip(event, '286', 788)" onmouseover="showTip(event, '286', 788)" class="rt">IRMode</span> <span class="o">=</span> <span class="uc">Proximity</span> <span class="pn">|</span> <span class="uc">Seek</span> <span class="pn">|</span> <span class="uc">Remote</span> <span class="pn">|</span> <span class="uc">RemoteA</span> <span class="pn">|</span> <span class="uc">SAlt</span> <span class="pn">|</span> <span class="uc">Calibrate</span> <span class="k">let</span> <span onmouseout="hideTip(event, '287', 789)" onmouseover="showTip(event, '287', 789)" class="fn">modeToUInt8</span> <span class="o">=</span> <span class="k">function</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '288', 790)" onmouseover="showTip(event, '288', 790)" class="uc">TouchMode</span> <span onmouseout="hideTip(event, '289', 791)" onmouseover="showTip(event, '289', 791)" class="uc">Touch</span> <span class="k">-&gt;</span> <span class="n">0uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '288', 792)" onmouseover="showTip(event, '288', 792)" class="uc">TouchMode</span> <span onmouseout="hideTip(event, '290', 793)" onmouseover="showTip(event, '290', 793)" class="uc">Bumps</span> <span class="k">-&gt;</span> <span class="n">1uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '291', 794)" onmouseover="showTip(event, '291', 794)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '292', 795)" onmouseover="showTip(event, '292', 795)" class="uc">Reflective</span> <span class="k">-&gt;</span> <span class="n">0uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '291', 796)" onmouseover="showTip(event, '291', 796)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '293', 797)" onmouseover="showTip(event, '293', 797)" class="uc">Ambient</span> <span class="k">-&gt;</span> <span class="n">1uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '291', 798)" onmouseover="showTip(event, '291', 798)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '294', 799)" onmouseover="showTip(event, '294', 799)" class="uc">Color</span> <span class="k">-&gt;</span> <span class="n">2uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '291', 800)" onmouseover="showTip(event, '291', 800)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '295', 801)" onmouseover="showTip(event, '295', 801)" class="uc">ReflectiveRaw</span> <span class="k">-&gt;</span> <span class="n">3uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '291', 802)" onmouseover="showTip(event, '291', 802)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '296', 803)" onmouseover="showTip(event, '296', 803)" class="uc">ReflectiveRgb</span> <span class="k">-&gt;</span> <span class="n">4uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '291', 804)" onmouseover="showTip(event, '291', 804)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '297', 805)" onmouseover="showTip(event, '297', 805)" class="uc">Calibration</span> <span class="k">-&gt;</span> <span class="n">5uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '298', 806)" onmouseover="showTip(event, '298', 806)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '299', 807)" onmouseover="showTip(event, '299', 807)" class="uc">Proximity</span> <span class="k">-&gt;</span> <span class="n">0uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '298', 808)" onmouseover="showTip(event, '298', 808)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '300', 809)" onmouseover="showTip(event, '300', 809)" class="uc">Seek</span> <span class="k">-&gt;</span> <span class="n">1uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '298', 810)" onmouseover="showTip(event, '298', 810)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '301', 811)" onmouseover="showTip(event, '301', 811)" class="uc">Remote</span> <span class="k">-&gt;</span> <span class="n">2uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '298', 812)" onmouseover="showTip(event, '298', 812)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '302', 813)" onmouseover="showTip(event, '302', 813)" class="uc">RemoteA</span> <span class="k">-&gt;</span> <span class="n">3uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '298', 814)" onmouseover="showTip(event, '298', 814)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '303', 815)" onmouseover="showTip(event, '303', 815)" class="uc">SAlt</span> <span class="k">-&gt;</span> <span class="n">4uy</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '298', 816)" onmouseover="showTip(event, '298', 816)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '304', 817)" onmouseover="showTip(event, '304', 817)" class="uc">Calibrate</span> <span class="k">-&gt;</span> <span class="n">5uy</span> </code></pre> <p>Different units are used depending on the sensor value:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '305', 818)" onmouseover="showTip(event, '305', 818)" class="rt">ReadDataType</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">SI</span> <span class="c">// a 4 bytes single (floating) value</span> <span class="pn">|</span> <span class="uc">Raw</span> <span class="c">// a 4 bytes integer</span> <span class="pn">|</span> <span class="uc">Percent</span> <span class="c">// a 1 byte percent</span> <span class="pn">|</span> <span class="uc">RGB</span> <span class="c">// 3 2 bytes integers</span> <span class="c">/// gets the byte length for each data type</span> <span class="k">let</span> <span onmouseout="hideTip(event, '306', 819)" onmouseover="showTip(event, '306', 819)" class="fn">readDataTypeLen</span> <span class="o">=</span> <span class="k">function</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 820)" onmouseover="showTip(event, '305', 820)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '307', 821)" onmouseover="showTip(event, '307', 821)" class="id">SI</span> <span class="k">-&gt;</span> <span class="n">4</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 822)" onmouseover="showTip(event, '305', 822)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '308', 823)" onmouseover="showTip(event, '308', 823)" class="id">Raw</span> <span class="k">-&gt;</span> <span class="n">4</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 824)" onmouseover="showTip(event, '305', 824)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '309', 825)" onmouseover="showTip(event, '309', 825)" class="id">Percent</span> <span class="k">-&gt;</span> <span class="n">1</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 826)" onmouseover="showTip(event, '305', 826)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '310', 827)" onmouseover="showTip(event, '310', 827)" class="id">RGB</span> <span class="k">-&gt;</span> <span class="n">6</span> </code></pre> <h2><a name="Read-command" class="anchor" href="#Read-command">Read command</a></h2> <p>Each of the datatypes corresponds to a different read opcode:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '311', 828)" onmouseover="showTip(event, '311', 828)" class="fn">readOpcode</span> <span class="o">=</span> <span class="k">function</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 829)" onmouseover="showTip(event, '305', 829)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '307', 830)" onmouseover="showTip(event, '307', 830)" class="id">SI</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '85', 831)" onmouseover="showTip(event, '85', 831)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '312', 832)" onmouseover="showTip(event, '312', 832)" class="id">InputDevice_ReadySI</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 833)" onmouseover="showTip(event, '305', 833)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '308', 834)" onmouseover="showTip(event, '308', 834)" class="id">Raw</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '85', 835)" onmouseover="showTip(event, '85', 835)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '313', 836)" onmouseover="showTip(event, '313', 836)" class="id">InputDevice_ReadyRaw</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 837)" onmouseover="showTip(event, '305', 837)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '310', 838)" onmouseover="showTip(event, '310', 838)" class="id">RGB</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '85', 839)" onmouseover="showTip(event, '85', 839)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '313', 840)" onmouseover="showTip(event, '313', 840)" class="id">InputDevice_ReadyRaw</span> <span class="c">// rgb is a specific Raw read</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '305', 841)" onmouseover="showTip(event, '305', 841)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '309', 842)" onmouseover="showTip(event, '309', 842)" class="id">Percent</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '85', 843)" onmouseover="showTip(event, '85', 843)" class="en">Opcode</span><span class="pn">.</span><span onmouseout="hideTip(event, '314', 844)" onmouseover="showTip(event, '314', 844)" class="id">InputDevice_ReadyPct</span> </code></pre> <p>With this opcode we can create a read command as we did previously. The <code>position</code> parameter is the position of the corresponding value in the response bytes.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '315', 845)" onmouseover="showTip(event, '315', 845)" class="fn">readCommand</span> <span class="pn">(</span><span onmouseout="hideTip(event, '316', 846)" onmouseover="showTip(event, '316', 846)" class="fn">inPort</span><span class="pn">,</span> <span onmouseout="hideTip(event, '317', 847)" onmouseover="showTip(event, '317', 847)" class="fn">dataType</span><span class="pn">,</span> <span onmouseout="hideTip(event, '318', 848)" onmouseover="showTip(event, '318', 848)" class="fn">mode</span><span class="pn">)</span> <span onmouseout="hideTip(event, '319', 849)" onmouseover="showTip(event, '319', 849)" class="fn">position</span> <span class="o">=</span> <span onmouseout="hideTip(event, '145', 850)" onmouseover="showTip(event, '145', 850)" class="uc">Direct</span><span class="pn">(</span><span onmouseout="hideTip(event, '311', 851)" onmouseover="showTip(event, '311', 851)" class="fn">readOpcode</span> <span onmouseout="hideTip(event, '317', 852)" onmouseover="showTip(event, '317', 852)" class="fn">dataType</span> <span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '126', 853)" onmouseover="showTip(event, '126', 853)" class="uc">Byte</span> <span class="n">0uy</span> <span onmouseout="hideTip(event, '274', 854)" onmouseover="showTip(event, '274', 854)" class="fn">inputPort</span> <span onmouseout="hideTip(event, '316', 855)" onmouseover="showTip(event, '316', 855)" class="fn">inPort</span> <span onmouseout="hideTip(event, '126', 856)" onmouseover="showTip(event, '126', 856)" class="uc">Byte</span> <span class="n">0uy</span> <span onmouseout="hideTip(event, '126', 857)" onmouseover="showTip(event, '126', 857)" class="uc">Byte</span> <span class="pn">(</span><span onmouseout="hideTip(event, '287', 858)" onmouseover="showTip(event, '287', 858)" class="fn">modeToUInt8</span> <span onmouseout="hideTip(event, '318', 859)" onmouseover="showTip(event, '318', 859)" class="fn">mode</span><span class="pn">)</span> <span onmouseout="hideTip(event, '126', 860)" onmouseover="showTip(event, '126', 860)" class="uc">Byte</span> <span class="n">1uy</span> <span onmouseout="hideTip(event, '138', 861)" onmouseover="showTip(event, '138', 861)" class="uc">GlobalIndex</span> <span class="pn">(</span><span onmouseout="hideTip(event, '117', 862)" onmouseover="showTip(event, '117', 862)" class="fn">uint8</span> <span onmouseout="hideTip(event, '319', 863)" onmouseover="showTip(event, '319', 863)" class="fn">position</span><span class="pn">)</span><span class="pn">]</span><span class="pn">)</span> </code></pre> <p>For a single sensor request, it's easy, just pass <code>0</code> for position, and read the value at the start of the response.</p> <p>The <code>send</code> function defined before was not waiting for a response. We create a <code>request</code> function the same way, but asks for a reply and use <code>AsyncRequest</code> to get a response. It checks the reply type (a byte just after response length).</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '320', 864)" onmouseover="showTip(event, '320', 864)" class="en">ReplyType</span> <span class="o">=</span> <span class="pn">|</span> <span class="en">DirectReply</span> <span class="o">=</span> <span class="n">0x02</span> <span class="pn">|</span> <span class="en">SystemReply</span> <span class="o">=</span> <span class="n">0x03</span> <span class="pn">|</span> <span class="en">DirectReplyError</span> <span class="o">=</span> <span class="n">0x04</span> <span class="pn">|</span> <span class="en">SystemReplyError</span> <span class="o">=</span> <span class="n">0x05</span> <span class="k">let</span> <span onmouseout="hideTip(event, '321', 865)" onmouseover="showTip(event, '321', 865)" class="fn">request</span> <span onmouseout="hideTip(event, '165', 866)" onmouseover="showTip(event, '165', 866)" class="fn">commands</span> <span onmouseout="hideTip(event, '164', 867)" onmouseover="showTip(event, '164', 867)" class="fn">globalSize</span> <span class="o">=</span> <span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '179', 868)" onmouseover="showTip(event, '179', 868)" class="d">brick</span><span class="pn">:</span> <span onmouseout="hideTip(event, '34', 869)" onmouseover="showTip(event, '34', 869)" class="d">Brick</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 870)" onmouseover="showTip(event, '18', 870)" class="k">async</span> <span class="pn">{</span> <span class="k">let</span> <span onmouseout="hideTip(event, '58', 871)" onmouseover="showTip(event, '58', 871)" class="fn">sequence</span> <span class="o">=</span> <span onmouseout="hideTip(event, '179', 872)" onmouseover="showTip(event, '179', 872)" class="d">brick</span><span class="pn">.</span><span onmouseout="hideTip(event, '180', 873)" onmouseover="showTip(event, '180', 873)" class="id">GetNextSequence</span><span class="pn">(</span><span class="pn">)</span> <span class="k">use</span> <span onmouseout="hideTip(event, '322', 874)" onmouseover="showTip(event, '322', 874)" class="d">data</span> <span class="o">=</span> <span onmouseout="hideTip(event, '165', 875)" onmouseover="showTip(event, '165', 875)" class="fn">commands</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '162', 876)" onmouseover="showTip(event, '162', 876)" class="fn">serialize</span> <span onmouseout="hideTip(event, '58', 877)" onmouseover="showTip(event, '58', 877)" class="fn">sequence</span> <span onmouseout="hideTip(event, '182', 878)" onmouseover="showTip(event, '182', 878)" class="m">CommandType</span><span class="pn">.</span><span onmouseout="hideTip(event, '81', 879)" onmouseover="showTip(event, '81', 879)" class="id">directReply</span> <span onmouseout="hideTip(event, '164', 880)" onmouseover="showTip(event, '164', 880)" class="fn">globalSize</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '28', 881)" onmouseover="showTip(event, '28', 881)" class="fn">response</span> <span class="o">=</span> <span onmouseout="hideTip(event, '179', 882)" onmouseover="showTip(event, '179', 882)" class="d">brick</span><span class="pn">.</span><span onmouseout="hideTip(event, '323', 883)" onmouseover="showTip(event, '323', 883)" class="id">AsyncRequest</span><span class="pn">(</span><span onmouseout="hideTip(event, '58', 884)" onmouseover="showTip(event, '58', 884)" class="fn">sequence</span><span class="pn">,</span> <span onmouseout="hideTip(event, '176', 885)" onmouseover="showTip(event, '176', 885)" class="vt">Memory</span><span class="pn">.</span><span onmouseout="hideTip(event, '183', 886)" onmouseover="showTip(event, '183', 886)" class="id">op_Implicit</span> <span onmouseout="hideTip(event, '322', 887)" onmouseover="showTip(event, '322', 887)" class="d">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '172', 888)" onmouseover="showTip(event, '172', 888)" class="id">Memory</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '324', 889)" onmouseover="showTip(event, '324', 889)" class="fn">replyType</span> <span class="o">=</span> <span onmouseout="hideTip(event, '112', 890)" onmouseover="showTip(event, '112', 890)" class="fn">enum</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '320', 891)" onmouseover="showTip(event, '320', 891)" class="en">ReplyType</span><span class="pn">&gt;</span> <span class="pn">(</span><span onmouseout="hideTip(event, '57', 892)" onmouseover="showTip(event, '57', 892)" class="fn">int</span> <span onmouseout="hideTip(event, '28', 893)" onmouseover="showTip(event, '28', 893)" class="fn">response</span><span class="pn">.</span><span onmouseout="hideTip(event, '325', 894)" onmouseover="showTip(event, '325', 894)" class="id">Span</span><span class="pn">.</span><span class="pn">[</span><span class="n">2</span><span class="pn">]</span><span class="pn">)</span> <span class="k">if</span> <span onmouseout="hideTip(event, '324', 895)" onmouseover="showTip(event, '324', 895)" class="fn">replyType</span> <span class="o">=</span> <span onmouseout="hideTip(event, '320', 896)" onmouseover="showTip(event, '320', 896)" class="en">ReplyType</span><span class="pn">.</span><span onmouseout="hideTip(event, '326', 897)" onmouseover="showTip(event, '326', 897)" class="id">DirectReplyError</span> <span class="o">||</span> <span onmouseout="hideTip(event, '324', 898)" onmouseover="showTip(event, '324', 898)" class="fn">replyType</span> <span class="o">=</span> <span onmouseout="hideTip(event, '320', 899)" onmouseover="showTip(event, '320', 899)" class="en">ReplyType</span><span class="pn">.</span><span onmouseout="hideTip(event, '327', 900)" onmouseover="showTip(event, '327', 900)" class="id">SystemReplyError</span> <span class="k">then</span> <span onmouseout="hideTip(event, '328', 901)" onmouseover="showTip(event, '328', 901)" class="fn">failwith</span> <span class="s">&quot;An error occurred&quot;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '28', 902)" onmouseover="showTip(event, '28', 902)" class="fn">response</span> <span class="pn">}</span> </code></pre> <p>To query multiple sensors at once, we can create multiple read commands with different positions, and send them in a single batch. It avoids multiple roundtrip through bluetooth which can be expensive. The problem is that setting response value position can be error prone.</p> <p>With the <code>readDataTypeLen</code> we can know the size of the value, and accumulate them to compute the offset. A <code>readLength</code> function that extracts the length from the triplet will make our life easier:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '329', 903)" onmouseover="showTip(event, '329', 903)" class="fn">readLength</span> <span class="pn">(</span><span class="id">_</span><span class="pn">,</span><span onmouseout="hideTip(event, '317', 904)" onmouseover="showTip(event, '317', 904)" class="fn">dataType</span><span class="pn">,</span><span class="id">_</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '306', 905)" onmouseover="showTip(event, '306', 905)" class="fn">readDataTypeLen</span> <span onmouseout="hideTip(event, '317', 906)" onmouseover="showTip(event, '317', 906)" class="fn">dataType</span> </code></pre> <p>We accumulate the sizes as offsets using a <code>mapFold</code>. The accumulator in mapFold takes a state (the offset) and an input (the sensor parameters), and outputs a value (the command built using the offset) and a new state (the new offset computed by adding the value length).</p> <p>This way we get a list of command with the rights offsets as well as the total length passed as globalSize.</p> <p>To interpret the result, we use <code>mapFold</code> again. Now the state is a <code>ReadOnlyMemory&lt;byte&gt;</code> starting at the 3rd byte (to skip the size and response status, the reason for the <code>Slice(3)</code>). For each item, we compute its length. The item is a pair of the sensors parameter and a slice containing the value. The state is sliced to skip the bytes from current value and start at the next one.</p> <p>We combine it with a call to request to have this function that takes a brick and a list of sensor parameters and returns a map of sensor parameters and their value as a <code>ReadOnlyMemory&lt;byte&gt;</code>.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '330', 907)" onmouseover="showTip(event, '330', 907)" class="fn">readAux</span> <span onmouseout="hideTip(event, '179', 908)" onmouseover="showTip(event, '179', 908)" class="d">brick</span> <span onmouseout="hideTip(event, '331', 909)" onmouseover="showTip(event, '331', 909)" class="fn">inputs</span> <span class="o">=</span> <span onmouseout="hideTip(event, '18', 910)" onmouseover="showTip(event, '18', 910)" class="k">async</span> <span class="pn">{</span> <span class="k">if</span> <span onmouseout="hideTip(event, '148', 911)" onmouseover="showTip(event, '148', 911)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '332', 912)" onmouseover="showTip(event, '332', 912)" class="id">isEmpty</span> <span onmouseout="hideTip(event, '331', 913)" onmouseover="showTip(event, '331', 913)" class="fn">inputs</span> <span class="k">then</span> <span class="k">return</span> <span onmouseout="hideTip(event, '25', 914)" onmouseover="showTip(event, '25', 914)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '33', 915)" onmouseover="showTip(event, '33', 915)" class="id">empty</span> <span class="k">else</span> <span class="k">let</span> <span onmouseout="hideTip(event, '165', 916)" onmouseover="showTip(event, '165', 916)" class="fn">commands</span><span class="pn">,</span> <span onmouseout="hideTip(event, '333', 917)" onmouseover="showTip(event, '333', 917)" class="fn">globalSize</span> <span class="o">=</span> <span onmouseout="hideTip(event, '331', 918)" onmouseover="showTip(event, '331', 918)" class="fn">inputs</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '148', 919)" onmouseover="showTip(event, '148', 919)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '334', 920)" onmouseover="showTip(event, '334', 920)" class="id">mapFold</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '335', 921)" onmouseover="showTip(event, '335', 921)" class="fn">offset</span> <span onmouseout="hideTip(event, '336', 922)" onmouseover="showTip(event, '336', 922)" class="fn">input</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '315', 923)" onmouseover="showTip(event, '315', 923)" class="fn">readCommand</span> <span onmouseout="hideTip(event, '336', 924)" onmouseover="showTip(event, '336', 924)" class="fn">input</span> <span onmouseout="hideTip(event, '335', 925)" onmouseover="showTip(event, '335', 925)" class="fn">offset</span><span class="pn">,</span> <span class="pn">(</span><span onmouseout="hideTip(event, '335', 926)" onmouseover="showTip(event, '335', 926)" class="fn">offset</span> <span class="o">+</span> <span onmouseout="hideTip(event, '329', 927)" onmouseover="showTip(event, '329', 927)" class="fn">readLength</span> <span onmouseout="hideTip(event, '336', 928)" onmouseover="showTip(event, '336', 928)" class="fn">input</span><span class="pn">)</span> <span class="pn">)</span> <span class="n">0</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '65', 929)" onmouseover="showTip(event, '65', 929)" class="fn">data</span> <span class="o">=</span> <span onmouseout="hideTip(event, '321', 930)" onmouseover="showTip(event, '321', 930)" class="fn">request</span> <span onmouseout="hideTip(event, '165', 931)" onmouseover="showTip(event, '165', 931)" class="fn">commands</span> <span class="pn">(</span><span onmouseout="hideTip(event, '64', 932)" onmouseover="showTip(event, '64', 932)" class="fn">uint16</span> <span onmouseout="hideTip(event, '333', 933)" onmouseover="showTip(event, '333', 933)" class="fn">globalSize</span><span class="pn">)</span> <span onmouseout="hideTip(event, '179', 934)" onmouseover="showTip(event, '179', 934)" class="d">brick</span> <span class="k">let</span> <span onmouseout="hideTip(event, '337', 935)" onmouseover="showTip(event, '337', 935)" class="fn">sensorsData</span> <span class="o">=</span> <span onmouseout="hideTip(event, '65', 936)" onmouseover="showTip(event, '65', 936)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '338', 937)" onmouseover="showTip(event, '338', 937)" class="id">Slice</span><span class="pn">(</span><span class="n">3</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '339', 938)" onmouseover="showTip(event, '339', 938)" class="fn">response</span> <span class="o">=</span> <span onmouseout="hideTip(event, '331', 939)" onmouseover="showTip(event, '331', 939)" class="fn">inputs</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '148', 940)" onmouseover="showTip(event, '148', 940)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '334', 941)" onmouseover="showTip(event, '334', 941)" class="id">mapFold</span> <span class="pn">(</span><span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '65', 942)" onmouseover="showTip(event, '65', 942)" class="fn">data</span><span class="pn">:</span> <span onmouseout="hideTip(event, '9', 943)" onmouseover="showTip(event, '9', 943)" class="vt">ReadOnlyMemory</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 944)" onmouseover="showTip(event, '10', 944)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">)</span> <span onmouseout="hideTip(event, '336', 945)" onmouseover="showTip(event, '336', 945)" class="fn">input</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '166', 946)" onmouseover="showTip(event, '166', 946)" class="fn">length</span> <span class="o">=</span> <span onmouseout="hideTip(event, '329', 947)" onmouseover="showTip(event, '329', 947)" class="fn">readLength</span> <span onmouseout="hideTip(event, '336', 948)" onmouseover="showTip(event, '336', 948)" class="fn">input</span> <span class="pn">(</span><span onmouseout="hideTip(event, '336', 949)" onmouseover="showTip(event, '336', 949)" class="fn">input</span><span class="pn">,</span> <span onmouseout="hideTip(event, '65', 950)" onmouseover="showTip(event, '65', 950)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '338', 951)" onmouseover="showTip(event, '338', 951)" class="id">Slice</span><span class="pn">(</span><span class="n">0</span><span class="pn">,</span> <span onmouseout="hideTip(event, '166', 952)" onmouseover="showTip(event, '166', 952)" class="fn">length</span><span class="pn">)</span><span class="pn">)</span><span class="pn">,</span> <span onmouseout="hideTip(event, '65', 953)" onmouseover="showTip(event, '65', 953)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '338', 954)" onmouseover="showTip(event, '338', 954)" class="id">Slice</span><span class="pn">(</span><span onmouseout="hideTip(event, '166', 955)" onmouseover="showTip(event, '166', 955)" class="fn">length</span><span class="pn">)</span><span class="pn">)</span> <span onmouseout="hideTip(event, '337', 956)" onmouseover="showTip(event, '337', 956)" class="fn">sensorsData</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '340', 957)" onmouseover="showTip(event, '340', 957)" class="fn">fst</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '25', 958)" onmouseover="showTip(event, '25', 958)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '341', 959)" onmouseover="showTip(event, '341', 959)" class="id">ofList</span> <span class="k">return</span> <span class="fn">response</span> <span class="pn">}</span> </code></pre> <h2><a name="Applicative" class="anchor" href="#Applicative">Applicative</a></h2> <p>We solved the problem of values offsets, but a few challenge remain. First the result is still in the form of a <code>ReadOnlyMemory&lt;byte&gt;</code>, and we should be careful to read it accordingly to the requested data. Then we have to be sure we don't try to look for values in the result that we did not request.</p> <p>If you've read previous posts already, you'll recognize the <code>Query&lt;'t&gt;</code> applicative. Here we will create a <code>Sensor&lt;'t&gt;</code> type:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '342', 960)" onmouseover="showTip(event, '342', 960)" class="rt">InputRequest</span> <span class="o">=</span> <span onmouseout="hideTip(event, '273', 961)" onmouseover="showTip(event, '273', 961)" class="rt">InputPort</span> <span class="pn">*</span> <span onmouseout="hideTip(event, '305', 962)" onmouseover="showTip(event, '305', 962)" class="rt">ReadDataType</span> <span class="pn">*</span> <span onmouseout="hideTip(event, '283', 963)" onmouseover="showTip(event, '283', 963)" class="rt">Mode</span> <span class="k">type</span> <span onmouseout="hideTip(event, '343', 964)" onmouseover="showTip(event, '343', 964)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 965)" onmouseover="showTip(event, '151', 965)" class="id">t</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Inputs</span><span class="pn">:</span> <span onmouseout="hideTip(event, '342', 966)" onmouseover="showTip(event, '342', 966)" class="rt">InputRequest</span> <span onmouseout="hideTip(event, '344', 967)" onmouseover="showTip(event, '344', 967)" class="rt">Set</span> <span class="fn">Get</span><span class="pn">:</span> <span onmouseout="hideTip(event, '25', 968)" onmouseover="showTip(event, '25', 968)" class="rt">Map</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '342', 969)" onmouseover="showTip(event, '342', 969)" class="rt">InputRequest</span><span class="pn">,</span> <span onmouseout="hideTip(event, '9', 970)" onmouseover="showTip(event, '9', 970)" class="vt">ReadOnlyMemory</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '10', 971)" onmouseover="showTip(event, '10', 971)" class="vt">byte</span><span class="pn">&gt;</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 972)" onmouseover="showTip(event, '151', 972)" class="id">t</span> <span class="pn">}</span> </code></pre> <p>It contains a set of inputs to request, and a function to extract a value of type <code>'t</code> from the result of our <code>readAux</code> function.</p> <p>For instance the simplest way to create a sensor from an input:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '345', 973)" onmouseover="showTip(event, '345', 973)" class="fn">input</span> <span class="pn">(</span><span onmouseout="hideTip(event, '346', 974)" onmouseover="showTip(event, '346', 974)" class="fn">req</span><span class="pn">:</span> <span onmouseout="hideTip(event, '342', 975)" onmouseover="showTip(event, '342', 975)" class="rt">InputRequest</span><span class="pn">)</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Inputs</span> <span class="o">=</span> <span onmouseout="hideTip(event, '344', 976)" onmouseover="showTip(event, '344', 976)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '347', 977)" onmouseover="showTip(event, '347', 977)" class="id">singleton</span> <span onmouseout="hideTip(event, '346', 978)" onmouseover="showTip(event, '346', 978)" class="fn">req</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '348', 979)" onmouseover="showTip(event, '348', 979)" class="fn">m</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '348', 980)" onmouseover="showTip(event, '348', 980)" class="fn">m</span><span class="pn">.</span><span class="pn">[</span><span onmouseout="hideTip(event, '346', 981)" onmouseover="showTip(event, '346', 981)" class="fn">req</span><span class="pn">]</span> <span class="pn">}</span> </code></pre> <p>It indicates that it should request the given input and gets it from the map. The result will be a <code>ReadOnlyMemory&lt;byte&gt;</code>.</p> <p>Creating a <code>read</code> functions that takes a <code>Sensor&lt;'t&gt;</code> and calls <code>readAux</code> is straightforward:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '349', 982)" onmouseover="showTip(event, '349', 982)" class="fn">read</span> <span class="pn">(</span><span onmouseout="hideTip(event, '350', 983)" onmouseover="showTip(event, '350', 983)" class="fn">sensor</span><span class="pn">:</span> <span onmouseout="hideTip(event, '343', 984)" onmouseover="showTip(event, '343', 984)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '151', 985)" onmouseover="showTip(event, '151', 985)" class="id">t</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '179', 986)" onmouseover="showTip(event, '179', 986)" class="d">brick</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 987)" onmouseover="showTip(event, '18', 987)" class="k">async</span> <span class="pn">{</span> <span class="k">let</span> <span onmouseout="hideTip(event, '351', 988)" onmouseover="showTip(event, '351', 988)" class="fn">inputs</span> <span class="o">=</span> <span onmouseout="hideTip(event, '344', 989)" onmouseover="showTip(event, '344', 989)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '352', 990)" onmouseover="showTip(event, '352', 990)" class="id">toList</span> <span onmouseout="hideTip(event, '350', 991)" onmouseover="showTip(event, '350', 991)" class="fn">sensor</span><span class="pn">.</span><span onmouseout="hideTip(event, '353', 992)" onmouseover="showTip(event, '353', 992)" class="id">Inputs</span> <span class="c">// gets the Map response for requested inputs</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '339', 993)" onmouseover="showTip(event, '339', 993)" class="fn">response</span> <span class="o">=</span> <span onmouseout="hideTip(event, '330', 994)" onmouseover="showTip(event, '330', 994)" class="fn">readAux</span> <span onmouseout="hideTip(event, '179', 995)" onmouseover="showTip(event, '179', 995)" class="d">brick</span> <span onmouseout="hideTip(event, '351', 996)" onmouseover="showTip(event, '351', 996)" class="fn">inputs</span> <span class="c">// use the sensor.Get to extract value from response</span> <span class="k">return</span> <span onmouseout="hideTip(event, '350', 997)" onmouseover="showTip(event, '350', 997)" class="fn">sensor</span><span class="pn">.</span><span onmouseout="hideTip(event, '354', 998)" onmouseover="showTip(event, '354', 998)" class="id">Get</span> <span onmouseout="hideTip(event, '339', 999)" onmouseover="showTip(event, '339', 999)" class="fn">response</span> <span class="pn">}</span> </code></pre> <p>Using a <code>Sensor&lt;'t&gt;</code> and <code>read</code>, no way to get it wrong.</p> <p>Now we want to create more complex sensors by combining simple ones.</p> <h3><a name="Ret" class="anchor" href="#Ret">Ret</a></h3> <p>We can create a pure sensor, a sensor that request no inputs and return a given value:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '355', 1000)" onmouseover="showTip(event, '355', 1000)" class="fn">ret</span> <span onmouseout="hideTip(event, '240', 1001)" onmouseover="showTip(event, '240', 1001)" class="fn">x</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Inputs</span> <span class="o">=</span> <span onmouseout="hideTip(event, '344', 1002)" onmouseover="showTip(event, '344', 1002)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '356', 1003)" onmouseover="showTip(event, '356', 1003)" class="id">empty</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '240', 1004)" onmouseover="showTip(event, '240', 1004)" class="fn">x</span> <span class="pn">}</span> </code></pre> <p>It will be useful later.</p> <h3><a name="Map" class="anchor" href="#Map">Map</a></h3> <p>We can define a <code>map</code> operation on it (yes, it's a functor). It takes a <code>'a -&gt; 'b</code> functions and changes a <code>Sensor&lt;'a&gt;</code> to a <code>Sensor&lt;'b&gt;</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '357', 1005)" onmouseover="showTip(event, '357', 1005)" class="fn">map</span> <span class="pn">(</span><span onmouseout="hideTip(event, '358', 1006)" onmouseover="showTip(event, '358', 1006)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1007)" onmouseover="showTip(event, '229', 1007)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1008)" onmouseover="showTip(event, '233', 1008)" class="id">b</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '359', 1009)" onmouseover="showTip(event, '359', 1009)" class="fn">s</span><span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1010)" onmouseover="showTip(event, '343', 1010)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1011)" onmouseover="showTip(event, '229', 1011)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1012)" onmouseover="showTip(event, '343', 1012)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1013)" onmouseover="showTip(event, '233', 1013)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Inputs</span> <span class="o">=</span> <span onmouseout="hideTip(event, '359', 1014)" onmouseover="showTip(event, '359', 1014)" class="fn">s</span><span class="pn">.</span><span onmouseout="hideTip(event, '353', 1015)" onmouseover="showTip(event, '353', 1015)" class="id">Inputs</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '348', 1016)" onmouseover="showTip(event, '348', 1016)" class="fn">m</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '359', 1017)" onmouseover="showTip(event, '359', 1017)" class="fn">s</span><span class="pn">.</span><span onmouseout="hideTip(event, '360', 1018)" onmouseover="showTip(event, '360', 1018)" class="id">Get</span> <span onmouseout="hideTip(event, '348', 1019)" onmouseover="showTip(event, '348', 1019)" class="fn">m</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '358', 1020)" onmouseover="showTip(event, '358', 1020)" class="fn">f</span> <span class="pn">}</span> </code></pre> <p>It requests the same inputs at the given sensor, gets its value and pass it to f.</p> <h3><a name="Map2" class="anchor" href="#Map2">Map2</a></h3> <p>More interesting, we can define a <code>map2</code> that takes to sensors, and pass their values to a function to compute a single result. This result will also be a sensor that request for inputs of both, and combine their results using f:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '361', 1021)" onmouseover="showTip(event, '361', 1021)" class="fn">map2</span> <span onmouseout="hideTip(event, '362', 1022)" onmouseover="showTip(event, '362', 1022)" class="fn">f</span> <span onmouseout="hideTip(event, '363', 1023)" onmouseover="showTip(event, '363', 1023)" class="fn">sx</span> <span onmouseout="hideTip(event, '364', 1024)" onmouseover="showTip(event, '364', 1024)" class="fn">sy</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Inputs</span> <span class="o">=</span> <span onmouseout="hideTip(event, '363', 1025)" onmouseover="showTip(event, '363', 1025)" class="fn">sx</span><span class="pn">.</span><span onmouseout="hideTip(event, '353', 1026)" onmouseover="showTip(event, '353', 1026)" class="id">Inputs</span> <span class="o">+</span> <span onmouseout="hideTip(event, '364', 1027)" onmouseover="showTip(event, '364', 1027)" class="fn">sy</span><span class="pn">.</span><span onmouseout="hideTip(event, '353', 1028)" onmouseover="showTip(event, '353', 1028)" class="id">Inputs</span> <span class="c">// union of inputs</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '348', 1029)" onmouseover="showTip(event, '348', 1029)" class="fn">m</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '240', 1030)" onmouseover="showTip(event, '240', 1030)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '363', 1031)" onmouseover="showTip(event, '363', 1031)" class="fn">sx</span><span class="pn">.</span><span onmouseout="hideTip(event, '360', 1032)" onmouseover="showTip(event, '360', 1032)" class="id">Get</span> <span onmouseout="hideTip(event, '348', 1033)" onmouseover="showTip(event, '348', 1033)" class="fn">m</span> <span class="c">// get value for sensor sx</span> <span class="k">let</span> <span onmouseout="hideTip(event, '365', 1034)" onmouseover="showTip(event, '365', 1034)" class="fn">y</span> <span class="o">=</span> <span onmouseout="hideTip(event, '364', 1035)" onmouseover="showTip(event, '364', 1035)" class="fn">sy</span><span class="pn">.</span><span onmouseout="hideTip(event, '366', 1036)" onmouseover="showTip(event, '366', 1036)" class="id">Get</span> <span onmouseout="hideTip(event, '348', 1037)" onmouseover="showTip(event, '348', 1037)" class="fn">m</span> <span class="c">// get value for sensor sy</span> <span onmouseout="hideTip(event, '362', 1038)" onmouseover="showTip(event, '362', 1038)" class="fn">f</span> <span onmouseout="hideTip(event, '240', 1039)" onmouseover="showTip(event, '240', 1039)" class="fn">x</span> <span onmouseout="hideTip(event, '365', 1040)" onmouseover="showTip(event, '365', 1040)" class="fn">y</span> <span class="pn">}</span> <span class="c">// combine the values using f</span> </code></pre> <p>We can use <code>map2</code> to <code>zip</code> sensors. It takes to sensors and create a single sensor that contains both values as a tuple:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '367', 1041)" onmouseover="showTip(event, '367', 1041)" class="fn">zip</span> <span onmouseout="hideTip(event, '363', 1042)" onmouseover="showTip(event, '363', 1042)" class="fn">sx</span> <span onmouseout="hideTip(event, '364', 1043)" onmouseover="showTip(event, '364', 1043)" class="fn">sy</span> <span class="o">=</span> <span onmouseout="hideTip(event, '361', 1044)" onmouseover="showTip(event, '361', 1044)" class="fn">map2</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '240', 1045)" onmouseover="showTip(event, '240', 1045)" class="fn">x</span> <span onmouseout="hideTip(event, '365', 1046)" onmouseover="showTip(event, '365', 1046)" class="fn">y</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '240', 1047)" onmouseover="showTip(event, '240', 1047)" class="fn">x</span><span class="pn">,</span><span onmouseout="hideTip(event, '365', 1048)" onmouseover="showTip(event, '365', 1048)" class="fn">y</span><span class="pn">)</span> <span onmouseout="hideTip(event, '363', 1049)" onmouseover="showTip(event, '363', 1049)" class="fn">sx</span> <span onmouseout="hideTip(event, '364', 1050)" onmouseover="showTip(event, '364', 1050)" class="fn">sy</span> </code></pre> <h3><a name="Apply" class="anchor" href="#Apply">Apply</a></h3> <p>The problem with map2, is that it works only with 2 sensors. For 3 sensors we would have to create a map3. And a map4, map5 etc.</p> <p>But in F#, every function is a function of 1 argument due to currying. A function of type <code>int -&gt; bool -&gt; string</code> can be used as a <code>int -&gt; (bool -&gt; string)</code>, it takes a single <code>int</code> argument and returns a function that takes a <code>bool</code> and returns a <code>string</code>.</p> <p>Passing this function to <code>map</code> with a sensor of type <code>Sensor&lt;int&gt;</code>, we get a <code>Sensor&lt;bool -&gt; string&gt;</code>. The meaning of this signature can seem obscure at first. It says that if you give this to the <code>read</code> function above, it will make a request and use the response values to build a <code>bool -&gt; string</code> result. if you pass a <code>bool</code> to this result, you get a <code>string</code>.</p> <p>But we would like the <code>bool</code> to also be read from a sensor. So we have a <code>Sensor&lt;bool -&gt; string&gt;</code> and a <code>Sensor&lt;bool&gt;</code>. We can obviously use <code>map2</code> on this pair of sensors. <code>map2</code> will pass the values of the sensors to the function passed as an argument. The first argument of this function will be a <code>bool -&gt; string</code>, the second a <code>bool</code>. We can pass the <code>bool</code> value to the <code>bool -&gt; string</code> function to get a <code>string</code>. The result will be a <code>Sensor&lt;string&gt;</code>.</p> <p>I used specific types to make it simpler by it works for any type:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '368', 1051)" onmouseover="showTip(event, '368', 1051)" class="fn">apply</span> <span class="pn">(</span><span onmouseout="hideTip(event, '369', 1052)" onmouseover="showTip(event, '369', 1052)" class="fn">sf</span><span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1053)" onmouseover="showTip(event, '343', 1053)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1054)" onmouseover="showTip(event, '229', 1054)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1055)" onmouseover="showTip(event, '233', 1055)" class="id">b</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '363', 1056)" onmouseover="showTip(event, '363', 1056)" class="fn">sx</span><span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1057)" onmouseover="showTip(event, '343', 1057)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1058)" onmouseover="showTip(event, '229', 1058)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1059)" onmouseover="showTip(event, '343', 1059)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1060)" onmouseover="showTip(event, '233', 1060)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '361', 1061)" onmouseover="showTip(event, '361', 1061)" class="fn">map2</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '358', 1062)" onmouseover="showTip(event, '358', 1062)" class="fn">f</span> <span onmouseout="hideTip(event, '240', 1063)" onmouseover="showTip(event, '240', 1063)" class="fn">x</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '358', 1064)" onmouseover="showTip(event, '358', 1064)" class="fn">f</span> <span onmouseout="hideTip(event, '240', 1065)" onmouseover="showTip(event, '240', 1065)" class="fn">x</span><span class="pn">)</span> <span onmouseout="hideTip(event, '369', 1066)" onmouseover="showTip(event, '369', 1066)" class="fn">sf</span> <span onmouseout="hideTip(event, '363', 1067)" onmouseover="showTip(event, '363', 1067)" class="fn">sx</span> </code></pre> <h3><a name="Typed-basic-sensors" class="anchor" href="#Typed-basic-sensors">Typed basic sensors</a></h3> <p>For a given data type, the conversion should always be the same. We create a function for each data type.</p> <p>Each of the inputXXX functions take a port and a mode are returns a typed sensor.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '370', 1068)" onmouseover="showTip(event, '370', 1068)" class="fn">typedInput</span> <span onmouseout="hideTip(event, '317', 1069)" onmouseover="showTip(event, '317', 1069)" class="fn">dataType</span> <span onmouseout="hideTip(event, '371', 1070)" onmouseover="showTip(event, '371', 1070)" class="fn">convert</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '372', 1071)" onmouseover="showTip(event, '372', 1071)" class="fn">port</span> <span onmouseout="hideTip(event, '318', 1072)" onmouseover="showTip(event, '318', 1072)" class="fn">mode</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '345', 1073)" onmouseover="showTip(event, '345', 1073)" class="fn">input</span> <span class="pn">(</span><span onmouseout="hideTip(event, '372', 1074)" onmouseover="showTip(event, '372', 1074)" class="fn">port</span><span class="pn">,</span> <span onmouseout="hideTip(event, '317', 1075)" onmouseover="showTip(event, '317', 1075)" class="fn">dataType</span><span class="pn">,</span> <span onmouseout="hideTip(event, '318', 1076)" onmouseover="showTip(event, '318', 1076)" class="fn">mode</span><span class="pn">)</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '357', 1077)" onmouseover="showTip(event, '357', 1077)" class="fn">map</span> <span onmouseout="hideTip(event, '371', 1078)" onmouseover="showTip(event, '371', 1078)" class="fn">convert</span> <span class="k">let</span> <span onmouseout="hideTip(event, '373', 1079)" onmouseover="showTip(event, '373', 1079)" class="fn">inputSi</span> <span class="o">=</span> <span onmouseout="hideTip(event, '370', 1080)" onmouseover="showTip(event, '370', 1080)" class="fn">typedInput</span> <span onmouseout="hideTip(event, '305', 1081)" onmouseover="showTip(event, '305', 1081)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '307', 1082)" onmouseover="showTip(event, '307', 1082)" class="id">SI</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '65', 1083)" onmouseover="showTip(event, '65', 1083)" class="fn">data</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '59', 1084)" onmouseover="showTip(event, '59', 1084)" class="rt">BitConverter</span><span class="pn">.</span><span onmouseout="hideTip(event, '374', 1085)" onmouseover="showTip(event, '374', 1085)" class="id">ToSingle</span><span class="pn">(</span><span onmouseout="hideTip(event, '65', 1086)" onmouseover="showTip(event, '65', 1086)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '325', 1087)" onmouseover="showTip(event, '325', 1087)" class="id">Span</span><span class="pn">)</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '375', 1088)" onmouseover="showTip(event, '375', 1088)" class="fn">inputRaw</span> <span class="o">=</span> <span onmouseout="hideTip(event, '370', 1089)" onmouseover="showTip(event, '370', 1089)" class="fn">typedInput</span> <span onmouseout="hideTip(event, '305', 1090)" onmouseover="showTip(event, '305', 1090)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '308', 1091)" onmouseover="showTip(event, '308', 1091)" class="id">Raw</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '65', 1092)" onmouseover="showTip(event, '65', 1092)" class="fn">data</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '59', 1093)" onmouseover="showTip(event, '59', 1093)" class="rt">BitConverter</span><span class="pn">.</span><span onmouseout="hideTip(event, '376', 1094)" onmouseover="showTip(event, '376', 1094)" class="id">ToInt32</span><span class="pn">(</span><span onmouseout="hideTip(event, '65', 1095)" onmouseover="showTip(event, '65', 1095)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '325', 1096)" onmouseover="showTip(event, '325', 1096)" class="id">Span</span><span class="pn">)</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '377', 1097)" onmouseover="showTip(event, '377', 1097)" class="fn">inputPct</span> <span class="o">=</span> <span onmouseout="hideTip(event, '370', 1098)" onmouseover="showTip(event, '370', 1098)" class="fn">typedInput</span> <span onmouseout="hideTip(event, '305', 1099)" onmouseover="showTip(event, '305', 1099)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '309', 1100)" onmouseover="showTip(event, '309', 1100)" class="id">Percent</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '65', 1101)" onmouseover="showTip(event, '65', 1101)" class="fn">data</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '57', 1102)" onmouseover="showTip(event, '57', 1102)" class="fn">int</span> <span onmouseout="hideTip(event, '65', 1103)" onmouseover="showTip(event, '65', 1103)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '325', 1104)" onmouseover="showTip(event, '325', 1104)" class="id">Span</span><span class="pn">.</span><span class="pn">[</span><span class="n">0</span><span class="pn">]</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '378', 1105)" onmouseover="showTip(event, '378', 1105)" class="fn">inputRgb</span> <span class="o">=</span> <span onmouseout="hideTip(event, '370', 1106)" onmouseover="showTip(event, '370', 1106)" class="fn">typedInput</span> <span onmouseout="hideTip(event, '305', 1107)" onmouseover="showTip(event, '305', 1107)" class="rt">ReadDataType</span><span class="pn">.</span><span onmouseout="hideTip(event, '310', 1108)" onmouseover="showTip(event, '310', 1108)" class="id">RGB</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '65', 1109)" onmouseover="showTip(event, '65', 1109)" class="fn">data</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '379', 1110)" onmouseover="showTip(event, '379', 1110)" class="fn">span</span> <span class="o">=</span> <span onmouseout="hideTip(event, '65', 1111)" onmouseover="showTip(event, '65', 1111)" class="fn">data</span><span class="pn">.</span><span onmouseout="hideTip(event, '325', 1112)" onmouseover="showTip(event, '325', 1112)" class="id">Span</span> <span class="k">let</span> <span onmouseout="hideTip(event, '380', 1113)" onmouseover="showTip(event, '380', 1113)" class="fn">r</span> <span class="o">=</span> <span onmouseout="hideTip(event, '59', 1114)" onmouseover="showTip(event, '59', 1114)" class="rt">BitConverter</span><span class="pn">.</span><span onmouseout="hideTip(event, '60', 1115)" onmouseover="showTip(event, '60', 1115)" class="id">ToUInt16</span><span class="pn">(</span><span onmouseout="hideTip(event, '379', 1116)" onmouseover="showTip(event, '379', 1116)" class="fn">span</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '381', 1117)" onmouseover="showTip(event, '381', 1117)" class="fn">g</span> <span class="o">=</span> <span onmouseout="hideTip(event, '59', 1118)" onmouseover="showTip(event, '59', 1118)" class="rt">BitConverter</span><span class="pn">.</span><span onmouseout="hideTip(event, '60', 1119)" onmouseover="showTip(event, '60', 1119)" class="id">ToUInt16</span><span class="pn">(</span><span onmouseout="hideTip(event, '379', 1120)" onmouseover="showTip(event, '379', 1120)" class="fn">span</span><span class="pn">.</span><span onmouseout="hideTip(event, '382', 1121)" onmouseover="showTip(event, '382', 1121)" class="id">Slice</span><span class="pn">(</span><span class="n">2</span><span class="pn">)</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '383', 1122)" onmouseover="showTip(event, '383', 1122)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '59', 1123)" onmouseover="showTip(event, '59', 1123)" class="rt">BitConverter</span><span class="pn">.</span><span onmouseout="hideTip(event, '60', 1124)" onmouseover="showTip(event, '60', 1124)" class="id">ToUInt16</span><span class="pn">(</span><span onmouseout="hideTip(event, '379', 1125)" onmouseover="showTip(event, '379', 1125)" class="fn">span</span><span class="pn">.</span><span onmouseout="hideTip(event, '382', 1126)" onmouseover="showTip(event, '382', 1126)" class="id">Slice</span><span class="pn">(</span><span class="n">4</span><span class="pn">)</span><span class="pn">)</span> <span onmouseout="hideTip(event, '57', 1127)" onmouseover="showTip(event, '57', 1127)" class="fn">int</span> <span onmouseout="hideTip(event, '380', 1128)" onmouseover="showTip(event, '380', 1128)" class="fn">r</span><span class="pn">,</span> <span onmouseout="hideTip(event, '57', 1129)" onmouseover="showTip(event, '57', 1129)" class="fn">int</span> <span onmouseout="hideTip(event, '381', 1130)" onmouseover="showTip(event, '381', 1130)" class="fn">g</span><span class="pn">,</span> <span onmouseout="hideTip(event, '57', 1131)" onmouseover="showTip(event, '57', 1131)" class="fn">int</span> <span onmouseout="hideTip(event, '383', 1132)" onmouseover="showTip(event, '383', 1132)" class="fn">b</span> <span class="pn">)</span> </code></pre> <p>Using this functions we define more interesting sensors</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="c">// the state of the touch sensor</span> <span class="k">type</span> <span onmouseout="hideTip(event, '384', 1133)" onmouseover="showTip(event, '384', 1133)" class="rt">ButtonState</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">Pushed</span> <span class="pn">|</span> <span class="uc">Released</span> <span class="c">// the colors of the color sensor</span> <span class="k">type</span> <span onmouseout="hideTip(event, '385', 1134)" onmouseover="showTip(event, '385', 1134)" class="rt">Color</span> <span class="o">=</span> <span class="pn">|</span> <span class="uc">Transparent</span> <span class="pn">|</span> <span class="uc">Black</span> <span class="pn">|</span> <span class="uc">Blue</span> <span class="pn">|</span> <span class="uc">Green</span> <span class="pn">|</span> <span class="uc">Yellow</span> <span class="pn">|</span> <span class="uc">Red</span> <span class="pn">|</span> <span class="uc">White</span> <span class="pn">|</span> <span class="uc">Brown</span> <span class="k">module</span> <span class="m">Sensors</span> <span class="o">=</span> <span class="k">module</span> <span onmouseout="hideTip(event, '385', 1135)" onmouseover="showTip(event, '385', 1135)" class="m">Color</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '386', 1136)" onmouseover="showTip(event, '386', 1136)" class="fn">reflective</span> <span onmouseout="hideTip(event, '372', 1137)" onmouseover="showTip(event, '372', 1137)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '377', 1138)" onmouseover="showTip(event, '377', 1138)" class="fn">inputPct</span> <span onmouseout="hideTip(event, '372', 1139)" onmouseover="showTip(event, '372', 1139)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '291', 1140)" onmouseover="showTip(event, '291', 1140)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '291', 1141)" onmouseover="showTip(event, '291', 1141)" class="rt">ColorMode</span><span class="pn">.</span><span onmouseout="hideTip(event, '292', 1142)" onmouseover="showTip(event, '292', 1142)" class="id">Reflective</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '387', 1143)" onmouseover="showTip(event, '387', 1143)" class="fn">ambient</span> <span onmouseout="hideTip(event, '372', 1144)" onmouseover="showTip(event, '372', 1144)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '377', 1145)" onmouseover="showTip(event, '377', 1145)" class="fn">inputPct</span> <span onmouseout="hideTip(event, '372', 1146)" onmouseover="showTip(event, '372', 1146)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '291', 1147)" onmouseover="showTip(event, '291', 1147)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '291', 1148)" onmouseover="showTip(event, '291', 1148)" class="rt">ColorMode</span><span class="pn">.</span><span onmouseout="hideTip(event, '293', 1149)" onmouseover="showTip(event, '293', 1149)" class="id">Ambient</span><span class="pn">)</span> <span class="c">// here we use the SI single result</span> <span class="c">// and map it to a Color</span> <span class="k">let</span> <span onmouseout="hideTip(event, '388', 1150)" onmouseover="showTip(event, '388', 1150)" class="fn">color</span> <span onmouseout="hideTip(event, '372', 1151)" onmouseover="showTip(event, '372', 1151)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '373', 1152)" onmouseover="showTip(event, '373', 1152)" class="fn">inputSi</span> <span onmouseout="hideTip(event, '372', 1153)" onmouseover="showTip(event, '372', 1153)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '291', 1154)" onmouseover="showTip(event, '291', 1154)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '291', 1155)" onmouseover="showTip(event, '291', 1155)" class="rt">ColorMode</span><span class="pn">.</span><span onmouseout="hideTip(event, '294', 1156)" onmouseover="showTip(event, '294', 1156)" class="id">Color</span><span class="pn">)</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '357', 1157)" onmouseover="showTip(event, '357', 1157)" class="fn">map</span> <span class="pn">(</span><span class="k">function</span> <span class="pn">|</span> <span class="n">1.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '389', 1158)" onmouseover="showTip(event, '389', 1158)" class="uc">Black</span> <span class="pn">|</span> <span class="n">2.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '390', 1159)" onmouseover="showTip(event, '390', 1159)" class="uc">Blue</span> <span class="pn">|</span> <span class="n">3.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '391', 1160)" onmouseover="showTip(event, '391', 1160)" class="uc">Green</span> <span class="pn">|</span> <span class="n">4.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '392', 1161)" onmouseover="showTip(event, '392', 1161)" class="uc">Yellow</span> <span class="pn">|</span> <span class="n">5.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '393', 1162)" onmouseover="showTip(event, '393', 1162)" class="uc">Red</span> <span class="pn">|</span> <span class="n">6.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '394', 1163)" onmouseover="showTip(event, '394', 1163)" class="uc">White</span> <span class="pn">|</span> <span class="n">7.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '395', 1164)" onmouseover="showTip(event, '395', 1164)" class="uc">Brown</span> <span class="pn">|</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '396', 1165)" onmouseover="showTip(event, '396', 1165)" class="uc">Transparent</span><span class="pn">)</span> <span class="k">module</span> <span onmouseout="hideTip(event, '308', 1166)" onmouseover="showTip(event, '308', 1166)" class="m">Raw</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '386', 1167)" onmouseover="showTip(event, '386', 1167)" class="fn">reflective</span> <span onmouseout="hideTip(event, '372', 1168)" onmouseover="showTip(event, '372', 1168)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '375', 1169)" onmouseover="showTip(event, '375', 1169)" class="fn">inputRaw</span> <span onmouseout="hideTip(event, '372', 1170)" onmouseover="showTip(event, '372', 1170)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '291', 1171)" onmouseover="showTip(event, '291', 1171)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '291', 1172)" onmouseover="showTip(event, '291', 1172)" class="rt">ColorMode</span><span class="pn">.</span><span onmouseout="hideTip(event, '295', 1173)" onmouseover="showTip(event, '295', 1173)" class="id">ReflectiveRaw</span><span class="pn">)</span> <span class="c">// this one use a RGB type, the result is read as a RGB triplet</span> <span class="k">let</span> <span onmouseout="hideTip(event, '397', 1174)" onmouseover="showTip(event, '397', 1174)" class="fn">rgb</span> <span onmouseout="hideTip(event, '372', 1175)" onmouseover="showTip(event, '372', 1175)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '378', 1176)" onmouseover="showTip(event, '378', 1176)" class="fn">inputRgb</span> <span onmouseout="hideTip(event, '372', 1177)" onmouseover="showTip(event, '372', 1177)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '291', 1178)" onmouseover="showTip(event, '291', 1178)" class="uc">ColorMode</span> <span onmouseout="hideTip(event, '291', 1179)" onmouseover="showTip(event, '291', 1179)" class="rt">ColorMode</span><span class="pn">.</span><span onmouseout="hideTip(event, '296', 1180)" onmouseover="showTip(event, '296', 1180)" class="id">ReflectiveRgb</span><span class="pn">)</span> <span class="k">module</span> <span class="m">IR</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '398', 1181)" onmouseover="showTip(event, '398', 1181)" class="fn">proximity</span> <span onmouseout="hideTip(event, '372', 1182)" onmouseover="showTip(event, '372', 1182)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '377', 1183)" onmouseover="showTip(event, '377', 1183)" class="fn">inputPct</span> <span onmouseout="hideTip(event, '372', 1184)" onmouseover="showTip(event, '372', 1184)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '298', 1185)" onmouseover="showTip(event, '298', 1185)" class="uc">IRMode</span> <span onmouseout="hideTip(event, '299', 1186)" onmouseover="showTip(event, '299', 1186)" class="uc">Proximity</span><span class="pn">)</span> <span class="k">module</span> <span onmouseout="hideTip(event, '289', 1187)" onmouseover="showTip(event, '289', 1187)" class="m">Touch</span> <span class="o">=</span> <span class="c">// the SI single result is mapped to Pushed/Released</span> <span class="k">let</span> <span onmouseout="hideTip(event, '399', 1188)" onmouseover="showTip(event, '399', 1188)" class="fn">button</span> <span onmouseout="hideTip(event, '372', 1189)" onmouseover="showTip(event, '372', 1189)" class="fn">port</span> <span class="o">=</span> <span onmouseout="hideTip(event, '373', 1190)" onmouseover="showTip(event, '373', 1190)" class="fn">inputSi</span> <span onmouseout="hideTip(event, '372', 1191)" onmouseover="showTip(event, '372', 1191)" class="fn">port</span> <span class="pn">(</span><span onmouseout="hideTip(event, '288', 1192)" onmouseover="showTip(event, '288', 1192)" class="uc">TouchMode</span> <span onmouseout="hideTip(event, '289', 1193)" onmouseover="showTip(event, '289', 1193)" class="uc">Touch</span><span class="pn">)</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '357', 1194)" onmouseover="showTip(event, '357', 1194)" class="fn">map</span> <span class="pn">(</span><span class="k">function</span> <span class="n">1.f</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '400', 1195)" onmouseover="showTip(event, '400', 1195)" class="uc">Pushed</span> <span class="pn">|</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '401', 1196)" onmouseover="showTip(event, '401', 1196)" class="uc">Released</span><span class="pn">)</span> </code></pre> <h3><a name="Operators" class="anchor" href="#Operators">Operators</a></h3> <p>Prior to F# 5.0 it is not possible to implement applicatives with computation expressions. Instead we can define <code>&lt;!&gt;</code> for <code>map</code> and <code>&lt;*&gt;</code> for <code>apply</code> to get infix syntax.</p> <p><code>&lt;!&gt;</code> takes a function on a left and a sensor on the right. We get a sensor with the argument applied. If it was a simple 1 argument function, we get a sensor of the result:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="pn">(</span><span class="o">&lt;!&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '357', 1197)" onmouseover="showTip(event, '357', 1197)" class="fn">map</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;*&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '368', 1198)" onmouseover="showTip(event, '368', 1198)" class="fn">apply</span> <span class="k">let</span> <span onmouseout="hideTip(event, '402', 1199)" onmouseover="showTip(event, '402', 1199)" class="fn">isRed</span> <span onmouseout="hideTip(event, '372', 1200)" onmouseover="showTip(event, '372', 1200)" class="fn">port</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1201)" onmouseover="showTip(event, '343', 1201)" class="rt">Sensor</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '403', 1202)" onmouseover="showTip(event, '403', 1202)" class="vt">bool</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '404', 1203)" onmouseover="showTip(event, '404', 1203)" class="fn">c</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '404', 1204)" onmouseover="showTip(event, '404', 1204)" class="fn">c</span> <span class="o">=</span> <span onmouseout="hideTip(event, '393', 1205)" onmouseover="showTip(event, '393', 1205)" class="uc">Red</span><span class="pn">)</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '405', 1206)" onmouseover="showTip(event, '405', 1206)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '406', 1207)" onmouseover="showTip(event, '406', 1207)" class="m">Color</span><span class="pn">.</span><span onmouseout="hideTip(event, '388', 1208)" onmouseover="showTip(event, '388', 1208)" class="id">color</span> <span onmouseout="hideTip(event, '372', 1209)" onmouseover="showTip(event, '372', 1209)" class="fn">port</span> </code></pre> <p>If the function take several parameters, we get a sensor of a function as a result. We can use it with <code>&lt;*&gt;</code>, the operator for <code>apply</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '407', 1210)" onmouseover="showTip(event, '407', 1210)" class="id">colorAndProximityIfPushed</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '343', 1211)" onmouseover="showTip(event, '343', 1211)" class="rt">Sensor</span><span class="pn">&lt;</span><span class="pn">(</span><span onmouseout="hideTip(event, '385', 1212)" onmouseover="showTip(event, '385', 1212)" class="rt">Color</span> <span class="pn">*</span> <span onmouseout="hideTip(event, '57', 1213)" onmouseover="showTip(event, '57', 1213)" class="vt">int</span><span class="pn">)</span> <span onmouseout="hideTip(event, '408', 1214)" onmouseover="showTip(event, '408', 1214)" class="rt">option</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '409', 1215)" onmouseover="showTip(event, '409', 1215)" class="fn">color</span> <span onmouseout="hideTip(event, '410', 1216)" onmouseover="showTip(event, '410', 1216)" class="fn">proximity</span> <span onmouseout="hideTip(event, '411', 1217)" onmouseover="showTip(event, '411', 1217)" class="fn">button</span> <span class="k">-&gt;</span> <span class="k">match</span> <span onmouseout="hideTip(event, '411', 1218)" onmouseover="showTip(event, '411', 1218)" class="fn">button</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '400', 1219)" onmouseover="showTip(event, '400', 1219)" class="uc">Pushed</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '30', 1220)" onmouseover="showTip(event, '30', 1220)" class="uc">Some</span> <span class="pn">(</span><span onmouseout="hideTip(event, '409', 1221)" onmouseover="showTip(event, '409', 1221)" class="fn">color</span><span class="pn">,</span> <span onmouseout="hideTip(event, '410', 1222)" onmouseover="showTip(event, '410', 1222)" class="fn">proximity</span><span class="pn">)</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '401', 1223)" onmouseover="showTip(event, '401', 1223)" class="uc">Released</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '32', 1224)" onmouseover="showTip(event, '32', 1224)" class="uc">None</span><span class="pn">)</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '405', 1225)" onmouseover="showTip(event, '405', 1225)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '406', 1226)" onmouseover="showTip(event, '406', 1226)" class="m">Color</span><span class="pn">.</span><span onmouseout="hideTip(event, '388', 1227)" onmouseover="showTip(event, '388', 1227)" class="id">color</span> <span onmouseout="hideTip(event, '275', 1228)" onmouseover="showTip(event, '275', 1228)" class="uc">In1</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '405', 1229)" onmouseover="showTip(event, '405', 1229)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '412', 1230)" onmouseover="showTip(event, '412', 1230)" class="m">IR</span><span class="pn">.</span><span onmouseout="hideTip(event, '398', 1231)" onmouseover="showTip(event, '398', 1231)" class="id">proximity</span> <span onmouseout="hideTip(event, '276', 1232)" onmouseover="showTip(event, '276', 1232)" class="uc">In2</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '405', 1233)" onmouseover="showTip(event, '405', 1233)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '413', 1234)" onmouseover="showTip(event, '413', 1234)" class="m">Touch</span><span class="pn">.</span><span onmouseout="hideTip(event, '399', 1235)" onmouseover="showTip(event, '399', 1235)" class="id">button</span> <span onmouseout="hideTip(event, '277', 1236)" onmouseover="showTip(event, '277', 1236)" class="uc">In3</span> </code></pre> <p>This is a composite sensor that gets the state from the Touch sensor in input 3, color from Color sensor in input 1, and proximity from IR sensor on input 2. It returns <code>None</code> when the button is released, and <code>Some(color, proximity)</code> when the button is pushed.</p> <h3><a name="Sensor-Computation-Expression" class="anchor" href="#Sensor-Computation-Expression">Sensor Computation Expression</a></h3> <p>With F# 5.0 we can replace these operators by a computation expression.</p> <p>We create a builder type as usual but implement <code>BindReturn</code> as <code>map</code> (with arguments swapped), and <code>MergeSources</code> as <code>zip</code>.</p> <p>We can also provide a <code>Bind2Return</code> for the 2 parameter cases as <code>map2</code>.</p> <p>The <code>Return</code> is implemented using <code>ret</code>, the pure value sensor:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '414', 1237)" onmouseover="showTip(event, '414', 1237)" class="rt">SensorBuilder</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">BindReturn</span><span class="pn">(</span><span onmouseout="hideTip(event, '415', 1238)" onmouseover="showTip(event, '415', 1238)" class="fn">x</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1239)" onmouseover="showTip(event, '229', 1239)" class="id">a</span> <span onmouseout="hideTip(event, '343', 1240)" onmouseover="showTip(event, '343', 1240)" class="rt">Sensor</span><span class="pn">,</span><span onmouseout="hideTip(event, '358', 1241)" onmouseover="showTip(event, '358', 1241)" class="fn">f</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1242)" onmouseover="showTip(event, '229', 1242)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1243)" onmouseover="showTip(event, '233', 1243)" class="id">b</span><span class="pn">)</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1244)" onmouseover="showTip(event, '233', 1244)" class="id">b</span> <span onmouseout="hideTip(event, '343', 1245)" onmouseover="showTip(event, '343', 1245)" class="rt">Sensor</span> <span class="o">=</span> <span onmouseout="hideTip(event, '357', 1246)" onmouseover="showTip(event, '357', 1246)" class="fn">map</span> <span onmouseout="hideTip(event, '358', 1247)" onmouseover="showTip(event, '358', 1247)" class="fn">f</span> <span onmouseout="hideTip(event, '415', 1248)" onmouseover="showTip(event, '415', 1248)" class="fn">x</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">MergeSources</span><span class="pn">(</span><span onmouseout="hideTip(event, '415', 1249)" onmouseover="showTip(event, '415', 1249)" class="fn">x</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1250)" onmouseover="showTip(event, '229', 1250)" class="id">a</span> <span onmouseout="hideTip(event, '343', 1251)" onmouseover="showTip(event, '343', 1251)" class="rt">Sensor</span><span class="pn">,</span> <span onmouseout="hideTip(event, '416', 1252)" onmouseover="showTip(event, '416', 1252)" class="fn">y</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1253)" onmouseover="showTip(event, '233', 1253)" class="id">b</span> <span onmouseout="hideTip(event, '343', 1254)" onmouseover="showTip(event, '343', 1254)" class="rt">Sensor</span><span class="pn">)</span> <span class="pn">:</span> <span class="pn">(</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1255)" onmouseover="showTip(event, '229', 1255)" class="id">a</span> <span class="pn">*</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1256)" onmouseover="showTip(event, '233', 1256)" class="id">b</span><span class="pn">)</span> <span onmouseout="hideTip(event, '343', 1257)" onmouseover="showTip(event, '343', 1257)" class="rt">Sensor</span> <span class="o">=</span> <span onmouseout="hideTip(event, '367', 1258)" onmouseover="showTip(event, '367', 1258)" class="fn">zip</span> <span onmouseout="hideTip(event, '415', 1259)" onmouseover="showTip(event, '415', 1259)" class="fn">x</span> <span onmouseout="hideTip(event, '416', 1260)" onmouseover="showTip(event, '416', 1260)" class="fn">y</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">Bind2Return</span><span class="pn">(</span><span onmouseout="hideTip(event, '415', 1261)" onmouseover="showTip(event, '415', 1261)" class="fn">x</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1262)" onmouseover="showTip(event, '229', 1262)" class="id">a</span> <span onmouseout="hideTip(event, '343', 1263)" onmouseover="showTip(event, '343', 1263)" class="rt">Sensor</span><span class="pn">,</span><span onmouseout="hideTip(event, '416', 1264)" onmouseover="showTip(event, '416', 1264)" class="fn">y</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1265)" onmouseover="showTip(event, '233', 1265)" class="id">b</span> <span onmouseout="hideTip(event, '343', 1266)" onmouseover="showTip(event, '343', 1266)" class="rt">Sensor</span><span class="pn">,</span><span onmouseout="hideTip(event, '417', 1267)" onmouseover="showTip(event, '417', 1267)" class="fn">f</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '229', 1268)" onmouseover="showTip(event, '229', 1268)" class="id">a</span><span class="pn">*</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '233', 1269)" onmouseover="showTip(event, '233', 1269)" class="id">b</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '418', 1270)" onmouseover="showTip(event, '418', 1270)" class="id">c</span><span class="pn">)</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '418', 1271)" onmouseover="showTip(event, '418', 1271)" class="id">c</span> <span onmouseout="hideTip(event, '343', 1272)" onmouseover="showTip(event, '343', 1272)" class="rt">Sensor</span> <span class="o">=</span> <span onmouseout="hideTip(event, '361', 1273)" onmouseover="showTip(event, '361', 1273)" class="fn">map2</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '240', 1274)" onmouseover="showTip(event, '240', 1274)" class="fn">x</span> <span onmouseout="hideTip(event, '365', 1275)" onmouseover="showTip(event, '365', 1275)" class="fn">y</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '417', 1276)" onmouseover="showTip(event, '417', 1276)" class="fn">f</span><span class="pn">(</span><span onmouseout="hideTip(event, '240', 1277)" onmouseover="showTip(event, '240', 1277)" class="fn">x</span><span class="pn">,</span><span onmouseout="hideTip(event, '365', 1278)" onmouseover="showTip(event, '365', 1278)" class="fn">y</span><span class="pn">)</span><span class="pn">)</span> <span onmouseout="hideTip(event, '415', 1279)" onmouseover="showTip(event, '415', 1279)" class="fn">x</span> <span onmouseout="hideTip(event, '416', 1280)" onmouseover="showTip(event, '416', 1280)" class="fn">y</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">Return</span> <span onmouseout="hideTip(event, '240', 1281)" onmouseover="showTip(event, '240', 1281)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '355', 1282)" onmouseover="showTip(event, '355', 1282)" class="fn">ret</span> <span onmouseout="hideTip(event, '240', 1283)" onmouseover="showTip(event, '240', 1283)" class="fn">x</span> <span class="k">let</span> <span onmouseout="hideTip(event, '419', 1284)" onmouseover="showTip(event, '419', 1284)" class="id">sensor</span> <span class="o">=</span> <span onmouseout="hideTip(event, '414', 1285)" onmouseover="showTip(event, '414', 1285)" class="fn">SensorBuilder</span><span class="pn">(</span><span class="pn">)</span> </code></pre> <p>Let's rewrite <code>colorAndProximityIfPushed</code> sensor with this computation expression:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '420', 1286)" onmouseover="showTip(event, '420', 1286)" class="id">colorWhenPushed</span> <span class="o">=</span> <span onmouseout="hideTip(event, '419', 1287)" onmouseover="showTip(event, '419', 1287)" class="k">sensor</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '409', 1288)" onmouseover="showTip(event, '409', 1288)" class="fn">color</span> <span class="o">=</span> <span onmouseout="hideTip(event, '405', 1289)" onmouseover="showTip(event, '405', 1289)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '406', 1290)" onmouseover="showTip(event, '406', 1290)" class="m">Color</span><span class="pn">.</span><span onmouseout="hideTip(event, '388', 1291)" onmouseover="showTip(event, '388', 1291)" class="id">color</span> <span onmouseout="hideTip(event, '275', 1292)" onmouseover="showTip(event, '275', 1292)" class="uc">In1</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '410', 1293)" onmouseover="showTip(event, '410', 1293)" class="fn">proximity</span> <span class="o">=</span> <span onmouseout="hideTip(event, '405', 1294)" onmouseover="showTip(event, '405', 1294)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '412', 1295)" onmouseover="showTip(event, '412', 1295)" class="m">IR</span><span class="pn">.</span><span onmouseout="hideTip(event, '398', 1296)" onmouseover="showTip(event, '398', 1296)" class="id">proximity</span> <span onmouseout="hideTip(event, '276', 1297)" onmouseover="showTip(event, '276', 1297)" class="uc">In2</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '411', 1298)" onmouseover="showTip(event, '411', 1298)" class="fn">button</span> <span class="o">=</span> <span onmouseout="hideTip(event, '405', 1299)" onmouseover="showTip(event, '405', 1299)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '413', 1300)" onmouseover="showTip(event, '413', 1300)" class="m">Touch</span><span class="pn">.</span><span onmouseout="hideTip(event, '399', 1301)" onmouseover="showTip(event, '399', 1301)" class="id">button</span> <span onmouseout="hideTip(event, '277', 1302)" onmouseover="showTip(event, '277', 1302)" class="uc">In3</span> <span class="k">return</span> <span class="k">match</span> <span onmouseout="hideTip(event, '411', 1303)" onmouseover="showTip(event, '411', 1303)" class="fn">button</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '400', 1304)" onmouseover="showTip(event, '400', 1304)" class="uc">Pushed</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '30', 1305)" onmouseover="showTip(event, '30', 1305)" class="uc">Some</span> <span class="pn">(</span><span onmouseout="hideTip(event, '409', 1306)" onmouseover="showTip(event, '409', 1306)" class="fn">color</span><span class="pn">,</span> <span onmouseout="hideTip(event, '410', 1307)" onmouseover="showTip(event, '410', 1307)" class="fn">proximity</span><span class="pn">)</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '401', 1308)" onmouseover="showTip(event, '401', 1308)" class="uc">Released</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '32', 1309)" onmouseover="showTip(event, '32', 1309)" class="uc">None</span> <span class="pn">}</span> </code></pre> <p>Notice the usage of and! to combine all the sensors together.</p> <p>We put it all together in a final sample:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '421', 1310)" onmouseover="showTip(event, '421', 1310)" class="fn">sample2</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="k">use</span> <span onmouseout="hideTip(event, '179', 1311)" onmouseover="showTip(event, '179', 1311)" class="d">brick</span> <span class="o">=</span> <span class="k">new</span> <span onmouseout="hideTip(event, '34', 1312)" onmouseover="showTip(event, '34', 1312)" class="d">Brick</span><span class="pn">(</span><span class="s">&quot;COM9&quot;</span><span class="pn">)</span> <span onmouseout="hideTip(event, '179', 1313)" onmouseover="showTip(event, '179', 1313)" class="d">brick</span><span class="pn">.</span><span onmouseout="hideTip(event, '271', 1314)" onmouseover="showTip(event, '271', 1314)" class="id">Connect</span><span class="pn">(</span><span class="pn">)</span> <span onmouseout="hideTip(event, '269', 1315)" onmouseover="showTip(event, '269', 1315)" class="k">lego</span> <span class="pn">{</span> <span class="k">for</span> <span onmouseout="hideTip(event, '272', 1316)" onmouseover="showTip(event, '272', 1316)" class="fn">i</span> <span class="k">in</span> <span class="n">0</span> <span class="o">..</span> <span class="n">100</span> <span class="k">do</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '422', 1317)" onmouseover="showTip(event, '422', 1317)" class="fn">value</span> <span class="o">=</span> <span onmouseout="hideTip(event, '349', 1318)" onmouseover="showTip(event, '349', 1318)" class="fn">read</span> <span class="pn">(</span> <span onmouseout="hideTip(event, '419', 1319)" onmouseover="showTip(event, '419', 1319)" class="k">sensor</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '423', 1320)" onmouseover="showTip(event, '423', 1320)" class="fn">color</span> <span class="o">=</span> <span onmouseout="hideTip(event, '405', 1321)" onmouseover="showTip(event, '405', 1321)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '406', 1322)" onmouseover="showTip(event, '406', 1322)" class="m">Color</span><span class="pn">.</span><span onmouseout="hideTip(event, '424', 1323)" onmouseover="showTip(event, '424', 1323)" class="m">Raw</span><span class="pn">.</span><span onmouseout="hideTip(event, '397', 1324)" onmouseover="showTip(event, '397', 1324)" class="id">rgb</span> <span onmouseout="hideTip(event, '275', 1325)" onmouseover="showTip(event, '275', 1325)" class="uc">In1</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '425', 1326)" onmouseover="showTip(event, '425', 1326)" class="fn">b</span> <span class="o">=</span> <span onmouseout="hideTip(event, '405', 1327)" onmouseover="showTip(event, '405', 1327)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '413', 1328)" onmouseover="showTip(event, '413', 1328)" class="m">Touch</span><span class="pn">.</span><span onmouseout="hideTip(event, '399', 1329)" onmouseover="showTip(event, '399', 1329)" class="id">button</span> <span onmouseout="hideTip(event, '276', 1330)" onmouseover="showTip(event, '276', 1330)" class="uc">In2</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '426', 1331)" onmouseover="showTip(event, '426', 1331)" class="fn">prox</span> <span class="o">=</span> <span onmouseout="hideTip(event, '405', 1332)" onmouseover="showTip(event, '405', 1332)" class="m">Sensors</span><span class="pn">.</span><span onmouseout="hideTip(event, '412', 1333)" onmouseover="showTip(event, '412', 1333)" class="m">IR</span><span class="pn">.</span><span onmouseout="hideTip(event, '398', 1334)" onmouseover="showTip(event, '398', 1334)" class="id">proximity</span> <span onmouseout="hideTip(event, '277', 1335)" onmouseover="showTip(event, '277', 1335)" class="uc">In3</span> <span class="k">match</span> <span onmouseout="hideTip(event, '425', 1336)" onmouseover="showTip(event, '425', 1336)" class="fn">b</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '400', 1337)" onmouseover="showTip(event, '400', 1337)" class="uc">Pushed</span> <span class="k">-&gt;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '30', 1338)" onmouseover="showTip(event, '30', 1338)" class="uc">Some</span> <span class="pn">(</span><span onmouseout="hideTip(event, '423', 1339)" onmouseover="showTip(event, '423', 1339)" class="fn">color</span><span class="pn">,</span><span onmouseout="hideTip(event, '426', 1340)" onmouseover="showTip(event, '426', 1340)" class="fn">prox</span><span class="pn">)</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '401', 1341)" onmouseover="showTip(event, '401', 1341)" class="uc">Released</span> <span class="k">-&gt;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '32', 1342)" onmouseover="showTip(event, '32', 1342)" class="uc">None</span> <span class="pn">}</span> <span class="pn">)</span> <span onmouseout="hideTip(event, '427', 1343)" onmouseover="showTip(event, '427', 1343)" class="fn">printfn</span> <span class="s">&quot;</span><span class="pf">%A</span><span class="s">&quot;</span> <span class="fn">value</span> <span class="pn">}</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '266', 1344)" onmouseover="showTip(event, '266', 1344)" class="fn">runSynchronously</span> <span onmouseout="hideTip(event, '179', 1345)" onmouseover="showTip(event, '179', 1345)" class="d">brick</span> </code></pre> <p>Take your time to extend it to send any command and combine any sensors in a friendly and readable way.</p> <p>The applicative computation expression for sensors provide a safe API over an error prone low level protocol. The syntax of computation expressions is also less obscure to newcomers than the <code>&lt;!&gt;</code> and <code>&lt;*&gt;</code> operators that can be a bit hard to explain.</p> <p>Now you know what to ask Santa for Xmas ! Happy Xmas !</p> <div class="fsdocs-tip" id="1">type Sequence = uint16</div> <div class="fsdocs-tip" id="2">Multiple items<br />val uint16: value: &#39;T -&gt; uint16 (requires member op_Explicit)<br /><br />--------------------<br />type uint16 = System.UInt16<br /><br />--------------------<br />type uint16&lt;&#39;Measure&gt; = uint16</div> <div class="fsdocs-tip" id="3">namespace System</div> <div class="fsdocs-tip" id="4">namespace System.Threading</div> <div class="fsdocs-tip" id="5">namespace System.Text</div> <div class="fsdocs-tip" id="6">namespace System.Buffers</div> <div class="fsdocs-tip" id="7">namespace System.Buffers.Binary</div> <div class="fsdocs-tip" id="8">type Dispatch = | Request of sequence: Sequence * (ReadOnlyMemory&lt;byte&gt; -&gt; unit) | Forward of sequence: Sequence * ReadOnlyMemory&lt;byte&gt;</div> <div class="fsdocs-tip" id="9">Multiple items<br />[&lt;Struct&gt;] type ReadOnlyMemory&lt;&#39;T&gt; = new: array: &#39;T array -&gt; unit + 1 overload member CopyTo: destination: Memory&lt;&#39;T&gt; -&gt; unit member Equals: obj: obj -&gt; bool + 1 overload member GetHashCode: unit -&gt; int member Pin: unit -&gt; MemoryHandle member Slice: start: int -&gt; ReadOnlyMemory&lt;&#39;T&gt; + 1 overload member ToArray: unit -&gt; &#39;T array member ToString: unit -&gt; string member TryCopyTo: destination: Memory&lt;&#39;T&gt; -&gt; bool static member op_Implicit: segment: ArraySegment&lt;&#39;T&gt; -&gt; ReadOnlyMemory&lt;&#39;T&gt; + 1 overload ...<br /><em>&lt;summary&gt;Represents a contiguous region of memory, similar to &lt;see cref=&quot;T:System.ReadOnlySpan`1&quot; /&gt;. Unlike &lt;see cref=&quot;T:System.ReadOnlySpan`1&quot; /&gt;, it is not a byref-like type.&lt;/summary&gt;<br />&lt;typeparam name=&quot;T&quot;&gt;The object type from which the contiguous region of memory will be read.&lt;/typeparam&gt;</em><br /><br />--------------------<br />ReadOnlyMemory ()<br />ReadOnlyMemory(array: &#39;T array) : ReadOnlyMemory&lt;&#39;T&gt;<br />ReadOnlyMemory(array: &#39;T array, start: int, length: int) : ReadOnlyMemory&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="10">Multiple items<br />val byte: value: &#39;T -&gt; byte (requires member op_Explicit)<br /><br />--------------------<br />type byte = Byte<br /><br />--------------------<br />type byte&lt;&#39;Measure&gt; = byte</div> <div class="fsdocs-tip" id="11">type unit = Unit</div> <div class="fsdocs-tip" id="12">val responseDispatcher: unit -&gt; MailboxProcessor&lt;Dispatch&gt;</div> <div class="fsdocs-tip" id="13">Multiple items<br />type MailboxProcessor&lt;&#39;Msg&gt; = interface IDisposable new: body: (MailboxProcessor&lt;&#39;Msg&gt; -&gt; Async&lt;unit&gt;) * ?cancellationToken: CancellationToken -&gt; MailboxProcessor&lt;&#39;Msg&gt; + 1 overload member Dispose: unit -&gt; unit member Post: message: &#39;Msg -&gt; unit member PostAndAsyncReply: buildMessage: (AsyncReplyChannel&lt;&#39;Reply&gt; -&gt; &#39;Msg) * ?timeout: int -&gt; Async&lt;&#39;Reply&gt; member PostAndReply: buildMessage: (AsyncReplyChannel&lt;&#39;Reply&gt; -&gt; &#39;Msg) * ?timeout: int -&gt; &#39;Reply member PostAndTryAsyncReply: buildMessage: (AsyncReplyChannel&lt;&#39;Reply&gt; -&gt; &#39;Msg) * ?timeout: int -&gt; Async&lt;&#39;Reply option&gt; member Receive: ?timeout: int -&gt; Async&lt;&#39;Msg&gt; member Scan: scanner: (&#39;Msg -&gt; Async&lt;&#39;T&gt; option) * ?timeout: int -&gt; Async&lt;&#39;T&gt; member TryPostAndReply: buildMessage: (AsyncReplyChannel&lt;&#39;Reply&gt; -&gt; &#39;Msg) * ?timeout: int -&gt; &#39;Reply option ...<br /><br />--------------------<br />new: body: (MailboxProcessor&lt;&#39;Msg&gt; -&gt; Async&lt;unit&gt;) * ?cancellationToken: CancellationToken -&gt; MailboxProcessor&lt;&#39;Msg&gt;<br />new: body: (MailboxProcessor&lt;&#39;Msg&gt; -&gt; Async&lt;unit&gt;) * isThrowExceptionAfterDisposed: bool * ?cancellationToken: CancellationToken -&gt; MailboxProcessor&lt;&#39;Msg&gt;</div> <div class="fsdocs-tip" id="14">static member MailboxProcessor.Start: body: (MailboxProcessor&lt;&#39;Msg&gt; -&gt; Async&lt;unit&gt;) * ?cancellationToken: CancellationToken -&gt; MailboxProcessor&lt;&#39;Msg&gt;<br />static member MailboxProcessor.Start: body: (MailboxProcessor&lt;&#39;Msg&gt; -&gt; Async&lt;unit&gt;) * isThrowExceptionAfterDisposed: bool * ?cancellationToken: CancellationToken -&gt; MailboxProcessor&lt;&#39;Msg&gt;</div> <div class="fsdocs-tip" id="15">val mailbox: MailboxProcessor&lt;Dispatch&gt;</div> <div class="fsdocs-tip" id="16">val loop: requests: Map&lt;Sequence,(ReadOnlyMemory&lt;byte&gt; -&gt; unit)&gt; -&gt; Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="17">val requests: Map&lt;Sequence,(ReadOnlyMemory&lt;byte&gt; -&gt; unit)&gt;</div> <div class="fsdocs-tip" id="18">val async: AsyncBuilder</div> <div class="fsdocs-tip" id="19">val message: Dispatch</div> <div class="fsdocs-tip" id="20">member MailboxProcessor.Receive: ?timeout: int -&gt; Async&lt;&#39;Msg&gt;</div> <div class="fsdocs-tip" id="21">val newMap: Map&lt;Sequence,(ReadOnlyMemory&lt;byte&gt; -&gt; unit)&gt;</div> <div class="fsdocs-tip" id="22">union case Dispatch.Request: sequence: Sequence * (ReadOnlyMemory&lt;byte&gt; -&gt; unit) -&gt; Dispatch</div> <div class="fsdocs-tip" id="23">val sequence: Sequence</div> <div class="fsdocs-tip" id="24">val reply: (ReadOnlyMemory&lt;byte&gt; -&gt; unit)</div> <div class="fsdocs-tip" id="25">Multiple items<br />module Map from Microsoft.FSharp.Collections<br /><br />--------------------<br />type Map&lt;&#39;Key,&#39;Value (requires comparison)&gt; = interface IReadOnlyDictionary&lt;&#39;Key,&#39;Value&gt; interface IReadOnlyCollection&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface ICollection&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface IDictionary&lt;&#39;Key,&#39;Value&gt; new: elements: (&#39;Key * &#39;Value) seq -&gt; Map&lt;&#39;Key,&#39;Value&gt; member Add: key: &#39;Key * value: &#39;Value -&gt; Map&lt;&#39;Key,&#39;Value&gt; ...<br /><br />--------------------<br />new: elements: (&#39;Key * &#39;Value) seq -&gt; Map&lt;&#39;Key,&#39;Value&gt;</div> <div class="fsdocs-tip" id="26">val add: key: &#39;Key -&gt; value: &#39;T -&gt; table: Map&lt;&#39;Key,&#39;T&gt; -&gt; Map&lt;&#39;Key,&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="27">union case Dispatch.Forward: sequence: Sequence * ReadOnlyMemory&lt;byte&gt; -&gt; Dispatch</div> <div class="fsdocs-tip" id="28">val response: ReadOnlyMemory&lt;byte&gt;</div> <div class="fsdocs-tip" id="29">val tryFind: key: &#39;Key -&gt; table: Map&lt;&#39;Key,&#39;T&gt; -&gt; &#39;T option (requires comparison)</div> <div class="fsdocs-tip" id="30">union case Option.Some: Value: &#39;T -&gt; Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="31">val remove: key: &#39;Key -&gt; table: Map&lt;&#39;Key,&#39;T&gt; -&gt; Map&lt;&#39;Key,&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="32">union case Option.None: Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="33">val empty&lt;&#39;Key,&#39;T (requires comparison)&gt; : Map&lt;&#39;Key,&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="34">Multiple items<br />type Brick = interface IDisposable new: name: string -&gt; Brick member AsyncRequest: sequence: Sequence * data: ReadOnlyMemory&lt;byte&gt; -&gt; Async&lt;ReadOnlyMemory&lt;byte&gt;&gt; member AsyncWrite: data: ReadOnlyMemory&lt;byte&gt; -&gt; Async&lt;unit&gt; member Connect: unit -&gt; unit member GetNextSequence: unit -&gt; uint16<br /><br />--------------------<br />new: name: string -&gt; Brick</div> <div class="fsdocs-tip" id="35">val name: string</div> <div class="fsdocs-tip" id="36">val port: IO.Ports.SerialPort</div> <div class="fsdocs-tip" id="37">namespace System.IO</div> <div class="fsdocs-tip" id="38">namespace System.IO.Ports</div> <div class="fsdocs-tip" id="39">Multiple items<br />type SerialPort = inherit Component new: unit -&gt; unit + 6 overloads member Close: unit -&gt; unit member DiscardInBuffer: unit -&gt; unit member DiscardOutBuffer: unit -&gt; unit member Open: unit -&gt; unit member Read: buffer: byte array * offset: int * count: int -&gt; int + 1 overload member ReadByte: unit -&gt; int member ReadChar: unit -&gt; int member ReadExisting: unit -&gt; string ...<br /><br />--------------------<br />IO.Ports.SerialPort() : IO.Ports.SerialPort<br />IO.Ports.SerialPort(container: ComponentModel.IContainer) : IO.Ports.SerialPort<br />IO.Ports.SerialPort(portName: string) : IO.Ports.SerialPort<br />IO.Ports.SerialPort(portName: string, baudRate: int) : IO.Ports.SerialPort<br />IO.Ports.SerialPort(portName: string, baudRate: int, parity: IO.Ports.Parity) : IO.Ports.SerialPort<br />IO.Ports.SerialPort(portName: string, baudRate: int, parity: IO.Ports.Parity, dataBits: int) : IO.Ports.SerialPort<br />IO.Ports.SerialPort(portName: string, baudRate: int, parity: IO.Ports.Parity, dataBits: int, stopBits: IO.Ports.StopBits) : IO.Ports.SerialPort</div> <div class="fsdocs-tip" id="40">val dispatcher: MailboxProcessor&lt;Dispatch&gt;</div> <div class="fsdocs-tip" id="41">val mutable sequence: int</div> <div class="fsdocs-tip" id="42">IO.Ports.SerialPort.Open() : unit</div> <div class="fsdocs-tip" id="43">val reader: IO.BinaryReader</div> <div class="fsdocs-tip" id="44">Multiple items<br />type BinaryReader = interface IDisposable new: input: Stream -&gt; unit + 2 overloads member Close: unit -&gt; unit member Dispose: unit -&gt; unit member PeekChar: unit -&gt; int member Read: unit -&gt; int + 4 overloads member Read7BitEncodedInt: unit -&gt; int member Read7BitEncodedInt64: unit -&gt; int64 member ReadBoolean: unit -&gt; bool member ReadByte: unit -&gt; byte ...<br /><em>&lt;summary&gt;Reads primitive data types as binary values in a specific encoding.&lt;/summary&gt;</em><br /><br />--------------------<br />IO.BinaryReader(input: IO.Stream) : IO.BinaryReader<br />IO.BinaryReader(input: IO.Stream, encoding: Encoding) : IO.BinaryReader<br />IO.BinaryReader(input: IO.Stream, encoding: Encoding, leaveOpen: bool) : IO.BinaryReader</div> <div class="fsdocs-tip" id="45">property IO.Ports.SerialPort.BaseStream: IO.Stream with get</div> <div class="fsdocs-tip" id="46">event IO.Ports.SerialPort.DataReceived: IEvent&lt;IO.Ports.SerialDataReceivedEventHandler,IO.Ports.SerialDataReceivedEventArgs&gt;</div> <div class="fsdocs-tip" id="47">Multiple items<br />module Event from Microsoft.FSharp.Control<br /><br />--------------------<br />type Event&lt;&#39;T&gt; = new: unit -&gt; Event&lt;&#39;T&gt; member Trigger: arg: &#39;T -&gt; unit member Publish: IEvent&lt;&#39;T&gt;<br /><br />--------------------<br />type Event&lt;&#39;Delegate,&#39;Args (requires delegate and &#39;Delegate :&gt; Delegate and reference type)&gt; = new: unit -&gt; Event&lt;&#39;Delegate,&#39;Args&gt; member Trigger: sender: objnull * args: &#39;Args -&gt; unit member Publish: IEvent&lt;&#39;Delegate,&#39;Args&gt;<br /><br />--------------------<br />new: unit -&gt; Event&lt;&#39;T&gt;<br /><br />--------------------<br />new: unit -&gt; Event&lt;&#39;Delegate,&#39;Args&gt;</div> <div class="fsdocs-tip" id="48">val add: callback: (&#39;T -&gt; unit) -&gt; sourceEvent: IEvent&lt;&#39;Del,&#39;T&gt; -&gt; unit (requires delegate and &#39;Del :&gt; Delegate)</div> <div class="fsdocs-tip" id="49">val e: IO.Ports.SerialDataReceivedEventArgs</div> <div class="fsdocs-tip" id="50">property IO.Ports.SerialDataReceivedEventArgs.EventType: IO.Ports.SerialData with get</div> <div class="fsdocs-tip" id="51">[&lt;Struct&gt;] type SerialData = | Chars = 1 | Eof = 2</div> <div class="fsdocs-tip" id="52">field IO.Ports.SerialData.Chars: IO.Ports.SerialData = 1</div> <div class="fsdocs-tip" id="53">val size: int16</div> <div class="fsdocs-tip" id="54">IO.BinaryReader.ReadInt16() : int16</div> <div class="fsdocs-tip" id="55">val response: byte array</div> <div class="fsdocs-tip" id="56">IO.BinaryReader.ReadBytes(count: int) : byte array</div> <div class="fsdocs-tip" id="57">Multiple items<br />val int: value: &#39;T -&gt; int (requires member op_Explicit)<br /><br />--------------------<br />type int = int32<br /><br />--------------------<br />type int&lt;&#39;Measure&gt; = int</div> <div class="fsdocs-tip" id="58">val sequence: uint16</div> <div class="fsdocs-tip" id="59">type BitConverter = static member DoubleToInt64Bits: value: float -&gt; int64 static member DoubleToUInt64Bits: value: float -&gt; uint64 static member GetBytes: value: bool -&gt; byte array + 12 overloads static member HalfToInt16Bits: value: Half -&gt; int16 static member HalfToUInt16Bits: value: Half -&gt; uint16 static member Int16BitsToHalf: value: int16 -&gt; Half static member Int32BitsToSingle: value: int -&gt; float32 static member Int64BitsToDouble: value: int64 -&gt; float static member SingleToInt32Bits: value: float32 -&gt; int static member SingleToUInt32Bits: value: float32 -&gt; uint32 ...<br /><em>&lt;summary&gt;Converts base data types to an array of bytes, and an array of bytes to base data types.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="60">BitConverter.ToUInt16(value: ReadOnlySpan&lt;byte&gt;) : uint16<br />BitConverter.ToUInt16(value: byte array, startIndex: int) : uint16</div> <div class="fsdocs-tip" id="61">member MailboxProcessor.Post: message: &#39;Msg -&gt; unit</div> <div class="fsdocs-tip" id="62">type Interlocked = static member Add: location1: byref&lt;int&gt; * value: int -&gt; int + 3 overloads static member And: location1: byref&lt;int&gt; * value: int -&gt; int + 3 overloads static member CompareExchange: location1: byref&lt;float&gt; * value: float * comparand: float -&gt; float + 13 overloads static member Decrement: location: byref&lt;int&gt; -&gt; int + 3 overloads static member Exchange: location1: byref&lt;float&gt; * value: float -&gt; float + 13 overloads static member Increment: location: byref&lt;int&gt; -&gt; int + 3 overloads static member MemoryBarrier: unit -&gt; unit static member MemoryBarrierProcessWide: unit -&gt; unit static member Or: location1: byref&lt;int&gt; * value: int -&gt; int + 3 overloads static member Read: location: byref&lt;int64&gt; -&gt; int64 + 1 overload<br /><em>&lt;summary&gt;Provides atomic operations for variables that are shared by multiple threads.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="63">Interlocked.Increment(location: byref&lt;uint64&gt;) : uint64<br />Interlocked.Increment(location: byref&lt;uint32&gt;) : uint32<br />Interlocked.Increment(location: byref&lt;int64&gt;) : int64<br />Interlocked.Increment(location: byref&lt;int&gt;) : int</div> <div class="fsdocs-tip" id="64">Multiple items<br />val uint16: value: &#39;T -&gt; uint16 (requires member op_Explicit)<br /><br />--------------------<br />type uint16 = UInt16<br /><br />--------------------<br />type uint16&lt;&#39;Measure&gt; = uint16</div> <div class="fsdocs-tip" id="65">val data: ReadOnlyMemory&lt;byte&gt;</div> <div class="fsdocs-tip" id="66">val task: Tasks.ValueTask</div> <div class="fsdocs-tip" id="67">IO.Stream.WriteAsync(buffer: ReadOnlyMemory&lt;byte&gt;, ?cancellationToken: CancellationToken) : Tasks.ValueTask<br />IO.Stream.WriteAsync(buffer: byte array, offset: int, count: int) : Tasks.Task<br />IO.Stream.WriteAsync(buffer: byte array, offset: int, count: int, cancellationToken: CancellationToken) : Tasks.Task</div> <div class="fsdocs-tip" id="68">property Tasks.ValueTask.IsCompleted: bool with get<br /><em>&lt;summary&gt;Gets a value that indicates whether this object represents a completed operation.&lt;/summary&gt;<br />&lt;returns&gt;&lt;see langword=&quot;true&quot; /&gt; if this object represents a completed operation; otherwise, &lt;see langword=&quot;false&quot; /&gt;.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="69">member AsyncBuilder.Return: value: &#39;T -&gt; Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="70">Multiple items<br />type Async = static member AsBeginEnd: computation: (&#39;Arg -&gt; Async&lt;&#39;T&gt;) -&gt; (&#39;Arg * AsyncCallback * objnull -&gt; IAsyncResult) * (IAsyncResult -&gt; &#39;T) * (IAsyncResult -&gt; unit) static member AwaitEvent: event: IEvent&lt;&#39;Del,&#39;T&gt; * ?cancelAction: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; (requires delegate and &#39;Del :&gt; Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -&gt; Async&lt;bool&gt; static member AwaitTask: task: Task&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -&gt; Async&lt;bool&gt; static member CancelDefaultToken: unit -&gt; unit static member Catch: computation: Async&lt;&#39;T&gt; -&gt; Async&lt;Choice&lt;&#39;T,exn&gt;&gt; static member Choice: computations: Async&lt;&#39;T option&gt; seq -&gt; Async&lt;&#39;T option&gt; static member FromBeginEnd: beginAction: (AsyncCallback * objnull -&gt; IAsyncResult) * endAction: (IAsyncResult -&gt; &#39;T) * ?cancelAction: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; + 3 overloads static member FromContinuations: callback: ((&#39;T -&gt; unit) * (exn -&gt; unit) * (OperationCanceledException -&gt; unit) -&gt; unit) -&gt; Async&lt;&#39;T&gt; ...<br /><br />--------------------<br />type Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="71">static member Async.AwaitTask: task: Tasks.Task -&gt; Async&lt;unit&gt;<br />static member Async.AwaitTask: task: Tasks.Task&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="72">Tasks.ValueTask.AsTask() : Tasks.Task</div> <div class="fsdocs-tip" id="73">val this: Brick</div> <div class="fsdocs-tip" id="74">member Brick.AsyncWrite: data: ReadOnlyMemory&lt;byte&gt; -&gt; Async&lt;unit&gt;</div> <div class="fsdocs-tip" id="75">member MailboxProcessor.PostAndAsyncReply: buildMessage: (AsyncReplyChannel&lt;&#39;Reply&gt; -&gt; &#39;Msg) * ?timeout: int -&gt; Async&lt;&#39;Reply&gt;</div> <div class="fsdocs-tip" id="76">val reply: AsyncReplyChannel&lt;ReadOnlyMemory&lt;byte&gt;&gt;</div> <div class="fsdocs-tip" id="77">member AsyncReplyChannel.Reply: value: &#39;Reply -&gt; unit</div> <div class="fsdocs-tip" id="78">type IDisposable = override Dispose: unit -&gt; unit<br /><em>&lt;summary&gt;Provides a mechanism for releasing unmanaged resources.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="79">IO.Ports.SerialPort.Close() : unit</div> <div class="fsdocs-tip" id="80">Multiple items<br />val byte: value: &#39;T -&gt; byte (requires member op_Explicit)<br /><br />--------------------<br />type byte = System.Byte<br /><br />--------------------<br />type byte&lt;&#39;Measure&gt; = byte</div> <div class="fsdocs-tip" id="81">val directReply: byte</div> <div class="fsdocs-tip" id="82">val directNoReply: byte</div> <div class="fsdocs-tip" id="83">val systemReply: byte</div> <div class="fsdocs-tip" id="84">val systemNoReply: byte</div> <div class="fsdocs-tip" id="85">[&lt;Struct&gt;] type Opcode = | UIRead_GetFirmware = 33034 | UIWrite_LED = 33307 | UIButton_Pressed = 33545 | UIDraw_Update = 33792 | UIDraw_Clean = 33793 | UIDraw_Pixel = 33794 | UIDraw_Line = 33795 | UIDraw_Circle = 33796 | UIDraw_Text = 33797 | UIDraw_FillRect = 33801 | UIDraw_Rect = 33802 | UIDraw_InverseRect = 33808 | UIDraw_SelectFont = 33809 | UIDraw_Topline = 33810 | UIDraw_FillWindow = 33811 | UIDraw_DotLine = 33813 | UIDraw_FillCircle = 33816 | UIDraw_BmpFile = 33820 | Sound_Break = 37888 | Sound_Tone = 37889 | Sound_Play = 37890 | Sound_Repeat = 37891 | Sound_Service = 37892 | InputDevice_GetTypeMode = 39173 | InputDevice_GetDeviceName = 39189 | InputDevice_GetModeName = 39190 | InputDevice_ReadyPct = 39195 | InputDevice_ReadyRaw = 39196 | InputDevice_ReadySI = 39197 | InputDevice_ClearAll = 39178 | InputDevice_ClearChanges = 39194 | InputRead = 154 | InputReadExt = 158 | InputReadSI = 157 | OutputStop = 163 | OutputPower = 164 | OutputSpeed = 165 | OutputStart = 166 | OutputPolarity = 167 | OutputReady = 170 | OutputStepPower = 172 | OutputTimePower = 173 | OutputStepSpeed = 174 | OutputTimeSpeed = 175 | OutputStepSync = 176 | OutputTimeSync = 177</div> <div class="fsdocs-tip" id="86">[&lt;Struct&gt;] type SystemOpcode = | BeginDownload = 146 | ContinueDownload = 147 | CloseFileHandle = 152 | CreateDirectory = 155 | DeleteFile = 156</div> <div class="fsdocs-tip" id="87">type Buffer = static member BlockCopy: src: Array * srcOffset: int * dst: Array * dstOffset: int * count: int -&gt; unit static member ByteLength: array: Array -&gt; int static member GetByte: array: Array * index: int -&gt; byte static member MemoryCopy: source: voidptr * destination: voidptr * destinationSizeInBytes: int64 * sourceBytesToCopy: int64 -&gt; unit + 1 overload static member SetByte: array: Array * index: int * value: byte -&gt; unit<br /><em>&lt;summary&gt;Manipulates arrays of primitive types.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="88">val write: value: byte -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="89">val value: byte</div> <div class="fsdocs-tip" id="90">val buffer: Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="91">Span.Slice(start: int) : Span&lt;byte&gt;<br />Span.Slice(start: int, length: int) : Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="92">val writeUint16: value: uint16 -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="93">val value: uint16</div> <div class="fsdocs-tip" id="94">type BinaryPrimitives = static member ReadDoubleBigEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; float static member ReadDoubleLittleEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; float static member ReadHalfBigEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; Half static member ReadHalfLittleEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; Half static member ReadInt128BigEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; Int128 static member ReadInt128LittleEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; Int128 static member ReadInt16BigEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; int16 static member ReadInt16LittleEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; int16 static member ReadInt32BigEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; int static member ReadInt32LittleEndian: source: ReadOnlySpan&lt;byte&gt; -&gt; int ...<br /><em>&lt;summary&gt;Reads bytes as primitives with specific endianness.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="95">BinaryPrimitives.WriteUInt16LittleEndian(destination: Span&lt;byte&gt;, value: uint16) : unit</div> <div class="fsdocs-tip" id="96">val writeUint16BE: value: uint16 -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="97">BinaryPrimitives.WriteUInt16BigEndian(destination: Span&lt;byte&gt;, value: uint16) : unit</div> <div class="fsdocs-tip" id="98">val writeUInt32: value: uint32 -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="99">val value: uint32</div> <div class="fsdocs-tip" id="100">Multiple items<br />val uint32: value: &#39;T -&gt; uint32 (requires member op_Explicit)<br /><br />--------------------<br />type uint32 = UInt32<br /><br />--------------------<br />type uint32&lt;&#39;Measure&gt; = uint&lt;&#39;Measure&gt;</div> <div class="fsdocs-tip" id="101">BinaryPrimitives.WriteUInt32LittleEndian(destination: Span&lt;byte&gt;, value: uint32) : unit</div> <div class="fsdocs-tip" id="102">val writeString: s: string -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="103">val s: string</div> <div class="fsdocs-tip" id="104">Multiple items<br />val string: value: &#39;T -&gt; string<br /><br />--------------------<br />type string = String</div> <div class="fsdocs-tip" id="105">val len: int</div> <div class="fsdocs-tip" id="106">type Encoding = interface ICloneable member Clone: unit -&gt; obj member Equals: value: obj -&gt; bool member GetByteCount: chars: nativeptr&lt;char&gt; * count: int -&gt; int + 5 overloads member GetBytes: chars: nativeptr&lt;char&gt; * charCount: int * bytes: nativeptr&lt;byte&gt; * byteCount: int -&gt; int + 7 overloads member GetCharCount: bytes: nativeptr&lt;byte&gt; * count: int -&gt; int + 3 overloads member GetChars: bytes: nativeptr&lt;byte&gt; * byteCount: int * chars: nativeptr&lt;char&gt; * charCount: int -&gt; int + 4 overloads member GetDecoder: unit -&gt; Decoder member GetEncoder: unit -&gt; Encoder member GetHashCode: unit -&gt; int ...<br /><em>&lt;summary&gt;Represents a character encoding.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="107">property Encoding.UTF8: Encoding with get<br /><em>&lt;summary&gt;Gets an encoding for the UTF-8 format.&lt;/summary&gt;<br />&lt;returns&gt;An encoding for the UTF-8 format.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="108">(extension) Encoding.GetBytes(chars: inref&lt;ReadOnlySequence&lt;char&gt;&gt;) : byte array<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />Encoding.GetBytes(s: string) : byte array<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />Encoding.GetBytes(chars: char array) : byte array<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />(extension) Encoding.GetBytes(chars: inref&lt;ReadOnlySequence&lt;char&gt;&gt;, writer: IBufferWriter&lt;byte&gt;) : int64<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />(extension) Encoding.GetBytes(chars: inref&lt;ReadOnlySequence&lt;char&gt;&gt;, bytes: Span&lt;byte&gt;) : int<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />(extension) Encoding.GetBytes(chars: ReadOnlySpan&lt;char&gt;, writer: IBufferWriter&lt;byte&gt;) : int64<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />Encoding.GetBytes(chars: ReadOnlySpan&lt;char&gt;, bytes: Span&lt;byte&gt;) : int<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />Encoding.GetBytes(s: string, index: int, count: int) : byte array<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />Encoding.GetBytes(chars: char array, index: int, count: int) : byte array<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />Encoding.GetBytes(chars: nativeptr&lt;char&gt;, charCount: int, bytes: nativeptr&lt;byte&gt;, byteCount: int) : int<br />&#160;&#160;&#160;<em>(+0 other overloads)</em></div> <div class="fsdocs-tip" id="109">(extension) String.AsSpan() : ReadOnlySpan&lt;char&gt;<br />(extension) String.AsSpan(start: int) : ReadOnlySpan&lt;char&gt;<br />(extension) String.AsSpan(startIndex: Index) : ReadOnlySpan&lt;char&gt;<br />(extension) String.AsSpan(range: Range) : ReadOnlySpan&lt;char&gt;<br />(extension) String.AsSpan(start: int, length: int) : ReadOnlySpan&lt;char&gt;</div> <div class="fsdocs-tip" id="110">val serializeOpcode: op: Opcode -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="111">val op: Opcode</div> <div class="fsdocs-tip" id="112">val enum: value: int32 -&gt; &#39;U (requires enum)</div> <div class="fsdocs-tip" id="113">val opcodeLength: code: &#39;a -&gt; int (requires enum and comparison)</div> <div class="fsdocs-tip" id="114">val code: &#39;a (requires enum and comparison)</div> <div class="fsdocs-tip" id="115">type Parameter = | Byte of uint8 | UShort of uint16 | UInt of uint32 | String of string | GlobalIndex of uint8</div> <div class="fsdocs-tip" id="116">[&lt;Struct&gt;] type Byte = member CompareTo: value: byte -&gt; int + 1 overload member Equals: obj: byte -&gt; bool + 1 overload member GetHashCode: unit -&gt; int member GetTypeCode: unit -&gt; TypeCode member ToString: unit -&gt; string + 3 overloads member TryFormat: utf8Destination: Span&lt;byte&gt; * bytesWritten: byref&lt;int&gt; * ?format: ReadOnlySpan&lt;char&gt; * ?provider: IFormatProvider -&gt; bool + 1 overload static member Clamp: value: byte * min: byte * max: byte -&gt; byte static member CreateChecked&lt;&#39;TOther (requires &#39;TOther :&gt; INumberBase&lt;&#39;TOther&gt;)&gt; : value: &#39;TOther -&gt; byte static member CreateSaturating&lt;&#39;TOther (requires &#39;TOther :&gt; INumberBase&lt;&#39;TOther&gt;)&gt; : value: &#39;TOther -&gt; byte static member CreateTruncating&lt;&#39;TOther (requires &#39;TOther :&gt; INumberBase&lt;&#39;TOther&gt;)&gt; : value: &#39;TOther -&gt; byte ...<br /><em>&lt;summary&gt;Represents an 8-bit unsigned integer.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="117">Multiple items<br />val uint8: value: &#39;T -&gt; uint8 (requires member op_Explicit)<br /><br />--------------------<br />type uint8 = Byte<br /><br />--------------------<br />type uint8&lt;&#39;Measure&gt; = byte&lt;&#39;Measure&gt;</div> <div class="fsdocs-tip" id="118">Multiple items<br />type String = interface IEnumerable&lt;char&gt; interface IEnumerable interface ICloneable interface IComparable interface IComparable&lt;string&gt; interface IConvertible interface IEquatable&lt;string&gt; interface IParsable&lt;string&gt; interface ISpanParsable&lt;string&gt; new: value: nativeptr&lt;char&gt; -&gt; unit + 8 overloads ...<br /><em>&lt;summary&gt;Represents text as a sequence of UTF-16 code units.&lt;/summary&gt;</em><br /><br />--------------------<br />String(value: nativeptr&lt;char&gt;) : String<br />String(value: char array) : String<br />String(value: ReadOnlySpan&lt;char&gt;) : String<br />String(value: nativeptr&lt;sbyte&gt;) : String<br />String(c: char, count: int) : String<br />String(value: nativeptr&lt;char&gt;, startIndex: int, length: int) : String<br />String(value: char array, startIndex: int, length: int) : String<br />String(value: nativeptr&lt;sbyte&gt;, startIndex: int, length: int) : String<br />String(value: nativeptr&lt;sbyte&gt;, startIndex: int, length: int, enc: Encoding) : String</div> <div class="fsdocs-tip" id="119">Multiple items<br />val byte: byte<br /><br />--------------------<br />type byte = Byte<br /><br />--------------------<br />type byte&lt;&#39;Measure&gt; = byte</div> <div class="fsdocs-tip" id="120">val short: byte</div> <div class="fsdocs-tip" id="121">Multiple items<br />val int: byte<br /><br />--------------------<br />type int = int32<br /><br />--------------------<br />type int&lt;&#39;Measure&gt; = int</div> <div class="fsdocs-tip" id="122">Multiple items<br />val string: byte<br /><br />--------------------<br />type string = String</div> <div class="fsdocs-tip" id="123">val globalIndex: byte</div> <div class="fsdocs-tip" id="124">val serializeParam: p: Parameter -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="125">val p: Parameter</div> <div class="fsdocs-tip" id="126">Multiple items<br />union case Parameter.Byte: uint8 -&gt; Parameter<br /><br />--------------------<br />[&lt;Struct&gt;] type Byte = member CompareTo: value: byte -&gt; int + 1 overload member Equals: obj: byte -&gt; bool + 1 overload member GetHashCode: unit -&gt; int member GetTypeCode: unit -&gt; TypeCode member ToString: unit -&gt; string + 3 overloads member TryFormat: utf8Destination: Span&lt;byte&gt; * bytesWritten: byref&lt;int&gt; * ?format: ReadOnlySpan&lt;char&gt; * ?provider: IFormatProvider -&gt; bool + 1 overload static member Clamp: value: byte * min: byte * max: byte -&gt; byte static member CreateChecked&lt;&#39;TOther (requires &#39;TOther :&gt; INumberBase&lt;&#39;TOther&gt;)&gt; : value: &#39;TOther -&gt; byte static member CreateSaturating&lt;&#39;TOther (requires &#39;TOther :&gt; INumberBase&lt;&#39;TOther&gt;)&gt; : value: &#39;TOther -&gt; byte static member CreateTruncating&lt;&#39;TOther (requires &#39;TOther :&gt; INumberBase&lt;&#39;TOther&gt;)&gt; : value: &#39;TOther -&gt; byte ...<br /><em>&lt;summary&gt;Represents an 8-bit unsigned integer.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="127">val v: uint8</div> <div class="fsdocs-tip" id="128">val b: Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="129">module ParamSize from 2020-12-03-applicative-computation-expressions-3</div> <div class="fsdocs-tip" id="130">val byte: byte</div> <div class="fsdocs-tip" id="131">union case Parameter.UShort: uint16 -&gt; Parameter</div> <div class="fsdocs-tip" id="132">val v: uint16</div> <div class="fsdocs-tip" id="133">union case Parameter.UInt: uint32 -&gt; Parameter</div> <div class="fsdocs-tip" id="134">val v: uint32</div> <div class="fsdocs-tip" id="135">val int: byte</div> <div class="fsdocs-tip" id="136">Multiple items<br />union case Parameter.String: string -&gt; Parameter<br /><br />--------------------<br />type String = interface IEnumerable&lt;char&gt; interface IEnumerable interface ICloneable interface IComparable interface IComparable&lt;string&gt; interface IConvertible interface IEquatable&lt;string&gt; interface IParsable&lt;string&gt; interface ISpanParsable&lt;string&gt; new: value: nativeptr&lt;char&gt; -&gt; unit + 8 overloads ...<br /><em>&lt;summary&gt;Represents text as a sequence of UTF-16 code units.&lt;/summary&gt;</em><br /><br />--------------------<br />String(value: nativeptr&lt;char&gt;) : String<br />String(value: char array) : String<br />String(value: ReadOnlySpan&lt;char&gt;) : String<br />String(value: nativeptr&lt;sbyte&gt;) : String<br />String(c: char, count: int) : String<br />String(value: nativeptr&lt;char&gt;, startIndex: int, length: int) : String<br />String(value: char array, startIndex: int, length: int) : String<br />String(value: nativeptr&lt;sbyte&gt;, startIndex: int, length: int) : String<br />String(value: nativeptr&lt;sbyte&gt;, startIndex: int, length: int, enc: Encoding) : String</div> <div class="fsdocs-tip" id="137">val string: byte</div> <div class="fsdocs-tip" id="138">union case Parameter.GlobalIndex: uint8 -&gt; Parameter</div> <div class="fsdocs-tip" id="139">val paramLength: _arg1: Parameter -&gt; int</div> <div class="fsdocs-tip" id="140">val l: string</div> <div class="fsdocs-tip" id="141">Encoding.GetByteCount(s: string) : int<br />Encoding.GetByteCount(chars: ReadOnlySpan&lt;char&gt;) : int<br />Encoding.GetByteCount(chars: char array) : int<br />Encoding.GetByteCount(chars: nativeptr&lt;char&gt;, count: int) : int<br />Encoding.GetByteCount(s: string, index: int, count: int) : int<br />Encoding.GetByteCount(chars: char array, index: int, count: int) : int</div> <div class="fsdocs-tip" id="142">type Command = | Direct of Opcode * Parameter list</div> <div class="fsdocs-tip" id="143">type &#39;T list = List&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="144">val length: _arg1: Command -&gt; int</div> <div class="fsdocs-tip" id="145">union case Command.Direct: Opcode * Parameter list -&gt; Command</div> <div class="fsdocs-tip" id="146">val code: Opcode</div> <div class="fsdocs-tip" id="147">val parameters: Parameter list</div> <div class="fsdocs-tip" id="148">Multiple items<br />module List from Microsoft.FSharp.Collections<br /><br />--------------------<br />type List&lt;&#39;T&gt; = | op_Nil | op_ColonColon of Head: &#39;T * Tail: &#39;T list interface IReadOnlyList&lt;&#39;T&gt; interface IReadOnlyCollection&lt;&#39;T&gt; interface IEnumerable interface IEnumerable&lt;&#39;T&gt; member Equals: List&lt;&#39;T&gt; * IEqualityComparer -&gt; bool member GetReverseIndex: rank: int * offset: int -&gt; int member GetSlice: startIndex: int option * endIndex: int option -&gt; &#39;T list static member Cons: head: &#39;T * tail: &#39;T list -&gt; &#39;T list member Head: &#39;T member IsEmpty: bool ...</div> <div class="fsdocs-tip" id="149">val sumBy: projection: (&#39;T -&gt; &#39;U) -&gt; list: &#39;T list -&gt; &#39;U (requires member (+) and member Zero)</div> <div class="fsdocs-tip" id="150">type Serializer&lt;&#39;t&gt; = delegate of &#39;t * Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="151">&#39;t</div> <div class="fsdocs-tip" id="152">val serializeAll: f: Serializer&lt;&#39;t&gt; -&gt; ps: &#39;t list -&gt; b: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="153">val f: Serializer&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="154">val ps: &#39;t list</div> <div class="fsdocs-tip" id="155">val p: &#39;t</div> <div class="fsdocs-tip" id="156">val t: &#39;t list</div> <div class="fsdocs-tip" id="157">val b&#39;: Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="158">abstract Serializer.Invoke: &#39;t * Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="159">val serializeCommand: command: Command -&gt; buffer: Span&lt;byte&gt; -&gt; Span&lt;byte&gt;</div> <div class="fsdocs-tip" id="160">val command: Command</div> <div class="fsdocs-tip" id="161">val p: Parameter list</div> <div class="fsdocs-tip" id="162">val serialize: sequence: uint16 -&gt; commandType: byte -&gt; globalSize: uint16 -&gt; commands: Command list -&gt; IMemoryOwner&lt;byte&gt;</div> <div class="fsdocs-tip" id="163">val commandType: byte</div> <div class="fsdocs-tip" id="164">val globalSize: uint16</div> <div class="fsdocs-tip" id="165">val commands: Command list</div> <div class="fsdocs-tip" id="166">val length: int</div> <div class="fsdocs-tip" id="167">val rental: IMemoryOwner&lt;byte&gt;</div> <div class="fsdocs-tip" id="168">type MemoryPool&lt;&#39;T&gt; = interface IDisposable member Dispose: unit -&gt; unit override Rent: ?minBufferSize: int -&gt; IMemoryOwner&lt;&#39;T&gt; member MaxBufferSize: int static member Shared: MemoryPool&lt;&#39;T&gt;<br /><em>&lt;summary&gt;Represents a pool of memory blocks.&lt;/summary&gt;<br />&lt;typeparam name=&quot;T&quot;&gt;The type of the items in the memory pool.&lt;/typeparam&gt;</em></div> <div class="fsdocs-tip" id="169">property MemoryPool.Shared: MemoryPool&lt;&#39;T&gt; with get<br /><em>&lt;summary&gt;Gets a singleton instance of a memory pool based on arrays.&lt;/summary&gt;<br />&lt;returns&gt;A singleton instance of a memory pool.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="170">MemoryPool.Rent(?minBufferSize: int) : IMemoryOwner&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="171">val mem: Memory&lt;byte&gt;</div> <div class="fsdocs-tip" id="172">property IMemoryOwner.Memory: Memory&lt;byte&gt; with get<br /><em>&lt;summary&gt;Gets the memory belonging to this owner.&lt;/summary&gt;<br />&lt;returns&gt;The memory belonging to this owner.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="173">Memory.Slice(start: int) : Memory&lt;byte&gt;<br />Memory.Slice(start: int, length: int) : Memory&lt;byte&gt;</div> <div class="fsdocs-tip" id="174">property Memory.Span: Span&lt;byte&gt; with get<br /><em>&lt;summary&gt;Returns a span from the current instance.&lt;/summary&gt;<br />&lt;returns&gt;A span created from the current &lt;see cref=&quot;T:System.Memory`1&quot; /&gt; object.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="175">type IMemoryOwner&lt;&#39;T&gt; = inherit IDisposable member Memory: Memory&lt;&#39;T&gt;<br /><em>&lt;summary&gt;Identifies the owner of a block of memory who is responsible for disposing of the underlying memory appropriately.&lt;/summary&gt;<br />&lt;typeparam name=&quot;T&quot;&gt;The type of elements to store in memory.&lt;/typeparam&gt;</em></div> <div class="fsdocs-tip" id="176">Multiple items<br />[&lt;Struct&gt;] type Memory&lt;&#39;T&gt; = new: array: &#39;T array -&gt; unit + 1 overload member CopyTo: destination: Memory&lt;&#39;T&gt; -&gt; unit member Equals: other: Memory&lt;&#39;T&gt; -&gt; bool + 1 overload member GetHashCode: unit -&gt; int member Pin: unit -&gt; MemoryHandle member Slice: start: int -&gt; Memory&lt;&#39;T&gt; + 1 overload member ToArray: unit -&gt; &#39;T array member ToString: unit -&gt; string member TryCopyTo: destination: Memory&lt;&#39;T&gt; -&gt; bool static member op_Implicit: segment: ArraySegment&lt;&#39;T&gt; -&gt; Memory&lt;&#39;T&gt; + 2 overloads ...<br /><em>&lt;summary&gt;Represents a contiguous region of memory.&lt;/summary&gt;<br />&lt;typeparam name=&quot;T&quot;&gt;The type of items in the &lt;see cref=&quot;T:System.Memory`1&quot; /&gt;.&lt;/typeparam&gt;</em><br /><br />--------------------<br />Memory ()<br />Memory(array: &#39;T array) : Memory&lt;&#39;T&gt;<br />Memory(array: &#39;T array, start: int, length: int) : Memory&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="177">IDisposable.Dispose() : unit</div> <div class="fsdocs-tip" id="178">val send: commands: Command list -&gt; brick: Brick -&gt; Async&lt;unit&gt;</div> <div class="fsdocs-tip" id="179">val brick: Brick</div> <div class="fsdocs-tip" id="180">member Brick.GetNextSequence: unit -&gt; uint16</div> <div class="fsdocs-tip" id="181">val memory: IMemoryOwner&lt;byte&gt;</div> <div class="fsdocs-tip" id="182">module CommandType from 2020-12-03-applicative-computation-expressions-3</div> <div class="fsdocs-tip" id="183">Memory.op_Implicit(array: &#39;T array) : Memory&lt;&#39;T&gt;<br />Memory.op_Implicit(memory: Memory&lt;&#39;T&gt;) : ReadOnlyMemory&lt;&#39;T&gt;<br />Memory.op_Implicit(segment: ArraySegment&lt;&#39;T&gt;) : Memory&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="184">type OutputPort = | A | B | C | D</div> <div class="fsdocs-tip" id="185">union case OutputPort.A: OutputPort</div> <div class="fsdocs-tip" id="186">union case OutputPort.B: OutputPort</div> <div class="fsdocs-tip" id="187">union case OutputPort.C: OutputPort</div> <div class="fsdocs-tip" id="188">union case OutputPort.D: OutputPort</div> <div class="fsdocs-tip" id="189">val port: p: OutputPort list -&gt; Parameter</div> <div class="fsdocs-tip" id="190">val p: OutputPort list</div> <div class="fsdocs-tip" id="191">val fold&lt;&#39;T,&#39;State&gt; : folder: (&#39;State -&gt; &#39;T -&gt; &#39;State) -&gt; state: &#39;State -&gt; list: &#39;T list -&gt; &#39;State</div> <div class="fsdocs-tip" id="192">val v: byte</div> <div class="fsdocs-tip" id="193">val p: OutputPort</div> <div class="fsdocs-tip" id="194">val startMotor: ports: OutputPort list -&gt; Command</div> <div class="fsdocs-tip" id="195">val ports: OutputPort list</div> <div class="fsdocs-tip" id="196">Opcode.OutputStart: Opcode = 166</div> <div class="fsdocs-tip" id="197">type Brake = | Brake | NoBrake static member toByte: b: Brake -&gt; Parameter</div> <div class="fsdocs-tip" id="198">val b: Brake</div> <div class="fsdocs-tip" id="199">Multiple items<br />union case Brake.Brake: Brake<br /><br />--------------------<br />type Brake = | Brake | NoBrake static member toByte: b: Brake -&gt; Parameter</div> <div class="fsdocs-tip" id="200">union case Brake.NoBrake: Brake</div> <div class="fsdocs-tip" id="201">val stopMotor: ports: OutputPort list -&gt; brake: Brake -&gt; Command</div> <div class="fsdocs-tip" id="202">val brake: Brake</div> <div class="fsdocs-tip" id="203">Opcode.OutputStop: Opcode = 163</div> <div class="fsdocs-tip" id="204">static member Brake.toByte: b: Brake -&gt; Parameter</div> <div class="fsdocs-tip" id="205">Multiple items<br />union case Power.Power: uint8 -&gt; Power<br /><br />--------------------<br />type Power = | Power of uint8</div> <div class="fsdocs-tip" id="206">type Power = | Power of uint8</div> <div class="fsdocs-tip" id="207">val power: p: int -&gt; Power</div> <div class="fsdocs-tip" id="208">val p: int</div> <div class="fsdocs-tip" id="209">val invalidArg: argumentName: string -&gt; message: string -&gt; &#39;T</div> <div class="fsdocs-tip" id="210">val outputReady: ports: OutputPort list -&gt; Command<br /><em>&#160;wait for the end of previous command</em></div> <div class="fsdocs-tip" id="211">Opcode.OutputReady: Opcode = 170</div> <div class="fsdocs-tip" id="212">val turnMotorAtPower: ports: OutputPort list -&gt; Power -&gt; Command</div> <div class="fsdocs-tip" id="213">val power: uint8</div> <div class="fsdocs-tip" id="214">Opcode.OutputPower: Opcode = 164</div> <div class="fsdocs-tip" id="215">val turnMotorAtSpeedForTime&#39;: ports: OutputPort list -&gt; speed: int -&gt; msRampUp: uint32 -&gt; msConstant: uint32 -&gt; msRampDown: uint32 -&gt; brake: Brake -&gt; Command</div> <div class="fsdocs-tip" id="216">val speed: int</div> <div class="fsdocs-tip" id="217">val msRampUp: uint32</div> <div class="fsdocs-tip" id="218">val msConstant: uint32</div> <div class="fsdocs-tip" id="219">val msRampDown: uint32</div> <div class="fsdocs-tip" id="220">Opcode.OutputTimeSpeed: Opcode = 175</div> <div class="fsdocs-tip" id="221">val turnMotorAtSpeedForTime: ports: OutputPort list -&gt; speed: int -&gt; msDuration: uint32 -&gt; brake: Brake -&gt; Command</div> <div class="fsdocs-tip" id="222">val msDuration: uint32</div> <div class="fsdocs-tip" id="223">val playTone: volume: uint8 -&gt; frequency: uint16 -&gt; duration: uint16 -&gt; Command</div> <div class="fsdocs-tip" id="224">val volume: uint8</div> <div class="fsdocs-tip" id="225">val frequency: uint16</div> <div class="fsdocs-tip" id="226">val duration: uint16</div> <div class="fsdocs-tip" id="227">Opcode.Sound_Tone: Opcode = 37889</div> <div class="fsdocs-tip" id="228">type Lego&lt;&#39;a&gt; = Brick -&gt; Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="229">&#39;a</div> <div class="fsdocs-tip" id="230">Multiple items<br />type LegoBuilder = new: unit -&gt; LegoBuilder member Bind: x: Async&lt;&#39;a&gt; * f: (&#39;a -&gt; Brick -&gt; Async&lt;&#39;b&gt;) -&gt; Lego&lt;&#39;b&gt; + 3 overloads member Combine: x: (Brick -&gt; Async&lt;unit&gt;) * y: (Brick -&gt; Async&lt;&#39;a&gt;) -&gt; Lego&lt;&#39;a&gt; member Delay: f: (unit -&gt; Brick -&gt; Async&lt;&#39;a&gt;) -&gt; (Brick -&gt; Async&lt;&#39;a&gt;) member For: values: &#39;T seq * body: (&#39;T -&gt; Brick -&gt; Async&lt;unit&gt;) -&gt; (Brick -&gt; Async&lt;unit&gt;) member Return: x: &#39;a -&gt; Lego&lt;&#39;a&gt; member ReturnFrom: x: &#39;e -&gt; &#39;e member Using: d: &#39;a * f: (&#39;b -&gt; &#39;a -&gt; Async&lt;&#39;c&gt;) -&gt; (&#39;b -&gt; Async&lt;&#39;c&gt;) (requires &#39;a :&gt; IDisposable) member Zero: unit -&gt; (&#39;d -&gt; Async&lt;unit&gt;)<br /><br />--------------------<br />new: unit -&gt; LegoBuilder</div> <div class="fsdocs-tip" id="231">val x: Lego&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="232">val f: (&#39;a -&gt; Brick -&gt; Async&lt;&#39;b&gt;)</div> <div class="fsdocs-tip" id="233">&#39;b</div> <div class="fsdocs-tip" id="234">member AsyncBuilder.Bind: computation: Async&lt;&#39;T&gt; * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt;</div> <div class="fsdocs-tip" id="235">val v: &#39;a</div> <div class="fsdocs-tip" id="236">val __: LegoBuilder</div> <div class="fsdocs-tip" id="237">val command: Command list</div> <div class="fsdocs-tip" id="238">val f: (unit -&gt; Brick -&gt; Async&lt;&#39;b&gt;)</div> <div class="fsdocs-tip" id="239">val x: Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="240">val x: &#39;a</div> <div class="fsdocs-tip" id="241">val x: &#39;e</div> <div class="fsdocs-tip" id="242">&#39;T</div> <div class="fsdocs-tip" id="243">val values: &#39;T seq</div> <div class="fsdocs-tip" id="244">Multiple items<br />val seq: sequence: &#39;T seq -&gt; &#39;T seq<br /><br />--------------------<br />type &#39;T seq = Collections.Generic.IEnumerable&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="245">val body: (&#39;T -&gt; Brick -&gt; Async&lt;unit&gt;)</div> <div class="fsdocs-tip" id="246">member AsyncBuilder.For: sequence: &#39;T seq * body: (&#39;T -&gt; Async&lt;unit&gt;) -&gt; Async&lt;unit&gt;</div> <div class="fsdocs-tip" id="247">val t: &#39;T</div> <div class="fsdocs-tip" id="248">val x: (Brick -&gt; Async&lt;unit&gt;)</div> <div class="fsdocs-tip" id="249">val y: (Brick -&gt; Async&lt;&#39;a&gt;)</div> <div class="fsdocs-tip" id="250">val ctx: Brick</div> <div class="fsdocs-tip" id="251">member AsyncBuilder.Combine: computation1: Async&lt;unit&gt; * computation2: Async&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="252">val f: (unit -&gt; Brick -&gt; Async&lt;&#39;a&gt;)</div> <div class="fsdocs-tip" id="253">member AsyncBuilder.Delay: generator: (unit -&gt; Async&lt;&#39;T&gt;) -&gt; Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="254">val ctx: &#39;d</div> <div class="fsdocs-tip" id="255">member AsyncBuilder.Zero: unit -&gt; Async&lt;unit&gt;</div> <div class="fsdocs-tip" id="256">val d: #IDisposable</div> <div class="fsdocs-tip" id="257">val f: (&#39;b -&gt; #IDisposable -&gt; Async&lt;&#39;c&gt;)</div> <div class="fsdocs-tip" id="258">val ctx: &#39;b</div> <div class="fsdocs-tip" id="259">member AsyncBuilder.Using: resource: &#39;T * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt; (requires &#39;T :&gt; IDisposable)</div> <div class="fsdocs-tip" id="260">val run: brick: Brick -&gt; f: Lego&lt;unit&gt; -&gt; CancellationTokenSource</div> <div class="fsdocs-tip" id="261">val f: Lego&lt;unit&gt;</div> <div class="fsdocs-tip" id="262">val cancelToken: CancellationTokenSource</div> <div class="fsdocs-tip" id="263">Multiple items<br />type CancellationTokenSource = interface IDisposable new: unit -&gt; unit + 3 overloads member Cancel: unit -&gt; unit + 1 overload member CancelAfter: millisecondsDelay: int -&gt; unit + 1 overload member CancelAsync: unit -&gt; Task member Dispose: unit -&gt; unit member TryReset: unit -&gt; bool static member CreateLinkedTokenSource: token: CancellationToken -&gt; CancellationTokenSource + 3 overloads member IsCancellationRequested: bool member Token: CancellationToken<br /><em>&lt;summary&gt;Signals to a &lt;see cref=&quot;T:System.Threading.CancellationToken&quot; /&gt; that it should be canceled.&lt;/summary&gt;</em><br /><br />--------------------<br />CancellationTokenSource() : CancellationTokenSource<br />CancellationTokenSource(millisecondsDelay: int) : CancellationTokenSource<br />CancellationTokenSource(delay: TimeSpan) : CancellationTokenSource<br />CancellationTokenSource(delay: TimeSpan, timeProvider: TimeProvider) : CancellationTokenSource</div> <div class="fsdocs-tip" id="264">static member Async.Start: computation: Async&lt;unit&gt; * ?cancellationToken: CancellationToken -&gt; unit</div> <div class="fsdocs-tip" id="265">property CancellationTokenSource.Token: CancellationToken with get<br /><em>&lt;summary&gt;Gets the &lt;see cref=&quot;T:System.Threading.CancellationToken&quot; /&gt; associated with this &lt;see cref=&quot;T:System.Threading.CancellationTokenSource&quot; /&gt;.&lt;/summary&gt;<br />&lt;exception cref=&quot;T:System.ObjectDisposedException&quot;&gt;The token source has been disposed.&lt;/exception&gt;<br />&lt;returns&gt;The &lt;see cref=&quot;T:System.Threading.CancellationToken&quot; /&gt; associated with this &lt;see cref=&quot;T:System.Threading.CancellationTokenSource&quot; /&gt;.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="266">val runSynchronously: brick: Brick -&gt; f: Lego&lt;&#39;a&gt; -&gt; &#39;a</div> <div class="fsdocs-tip" id="267">val f: Lego&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="268">static member Async.RunSynchronously: computation: Async&lt;&#39;T&gt; * ?timeout: int * ?cancellationToken: CancellationToken -&gt; &#39;T</div> <div class="fsdocs-tip" id="269">val lego: LegoBuilder</div> <div class="fsdocs-tip" id="270">val sample: unit -&gt; unit</div> <div class="fsdocs-tip" id="271">member Brick.Connect: unit -&gt; unit</div> <div class="fsdocs-tip" id="272">val i: int</div> <div class="fsdocs-tip" id="273">type InputPort = | In1 | In2 | In3 | In4 | InA | InB | InC | InD</div> <div class="fsdocs-tip" id="274">val inputPort: (InputPort -&gt; Parameter)<br /><em>&#160;gets the binary code for an input port</em></div> <div class="fsdocs-tip" id="275">union case InputPort.In1: InputPort</div> <div class="fsdocs-tip" id="276">union case InputPort.In2: InputPort</div> <div class="fsdocs-tip" id="277">union case InputPort.In3: InputPort</div> <div class="fsdocs-tip" id="278">union case InputPort.In4: InputPort</div> <div class="fsdocs-tip" id="279">union case InputPort.InA: InputPort</div> <div class="fsdocs-tip" id="280">union case InputPort.InB: InputPort</div> <div class="fsdocs-tip" id="281">union case InputPort.InC: InputPort</div> <div class="fsdocs-tip" id="282">union case InputPort.InD: InputPort</div> <div class="fsdocs-tip" id="283">type Mode = | TouchMode of TouchMode | ColorMode of ColorMode | IRMode of IRMode</div> <div class="fsdocs-tip" id="284">type TouchMode = | Touch | Bumps</div> <div class="fsdocs-tip" id="285">type ColorMode = | Reflective | Ambient | Color | ReflectiveRaw | ReflectiveRgb | Calibration</div> <div class="fsdocs-tip" id="286">type IRMode = | Proximity | Seek | Remote | RemoteA | SAlt | Calibrate</div> <div class="fsdocs-tip" id="287">val modeToUInt8: _arg1: Mode -&gt; byte</div> <div class="fsdocs-tip" id="288">Multiple items<br />union case Mode.TouchMode: TouchMode -&gt; Mode<br /><br />--------------------<br />type TouchMode = | Touch | Bumps</div> <div class="fsdocs-tip" id="289">union case TouchMode.Touch: TouchMode</div> <div class="fsdocs-tip" id="290">union case TouchMode.Bumps: TouchMode</div> <div class="fsdocs-tip" id="291">Multiple items<br />union case Mode.ColorMode: ColorMode -&gt; Mode<br /><br />--------------------<br />type ColorMode = | Reflective | Ambient | Color | ReflectiveRaw | ReflectiveRgb | Calibration</div> <div class="fsdocs-tip" id="292">union case ColorMode.Reflective: ColorMode</div> <div class="fsdocs-tip" id="293">union case ColorMode.Ambient: ColorMode</div> <div class="fsdocs-tip" id="294">union case ColorMode.Color: ColorMode</div> <div class="fsdocs-tip" id="295">union case ColorMode.ReflectiveRaw: ColorMode</div> <div class="fsdocs-tip" id="296">union case ColorMode.ReflectiveRgb: ColorMode</div> <div class="fsdocs-tip" id="297">union case ColorMode.Calibration: ColorMode</div> <div class="fsdocs-tip" id="298">Multiple items<br />union case Mode.IRMode: IRMode -&gt; Mode<br /><br />--------------------<br />type IRMode = | Proximity | Seek | Remote | RemoteA | SAlt | Calibrate</div> <div class="fsdocs-tip" id="299">union case IRMode.Proximity: IRMode</div> <div class="fsdocs-tip" id="300">union case IRMode.Seek: IRMode</div> <div class="fsdocs-tip" id="301">union case IRMode.Remote: IRMode</div> <div class="fsdocs-tip" id="302">union case IRMode.RemoteA: IRMode</div> <div class="fsdocs-tip" id="303">union case IRMode.SAlt: IRMode</div> <div class="fsdocs-tip" id="304">union case IRMode.Calibrate: IRMode</div> <div class="fsdocs-tip" id="305">type ReadDataType = | SI | Raw | Percent | RGB</div> <div class="fsdocs-tip" id="306">val readDataTypeLen: _arg1: ReadDataType -&gt; int<br /><em>&#160;gets the byte length for each data type</em></div> <div class="fsdocs-tip" id="307">union case ReadDataType.SI: ReadDataType</div> <div class="fsdocs-tip" id="308">union case ReadDataType.Raw: ReadDataType</div> <div class="fsdocs-tip" id="309">union case ReadDataType.Percent: ReadDataType</div> <div class="fsdocs-tip" id="310">union case ReadDataType.RGB: ReadDataType</div> <div class="fsdocs-tip" id="311">val readOpcode: _arg1: ReadDataType -&gt; Opcode</div> <div class="fsdocs-tip" id="312">Opcode.InputDevice_ReadySI: Opcode = 39197</div> <div class="fsdocs-tip" id="313">Opcode.InputDevice_ReadyRaw: Opcode = 39196</div> <div class="fsdocs-tip" id="314">Opcode.InputDevice_ReadyPct: Opcode = 39195</div> <div class="fsdocs-tip" id="315">val readCommand: inPort: InputPort * dataType: ReadDataType * mode: Mode -&gt; position: int -&gt; Command</div> <div class="fsdocs-tip" id="316">val inPort: InputPort</div> <div class="fsdocs-tip" id="317">val dataType: ReadDataType</div> <div class="fsdocs-tip" id="318">val mode: Mode</div> <div class="fsdocs-tip" id="319">val position: int</div> <div class="fsdocs-tip" id="320">[&lt;Struct&gt;] type ReplyType = | DirectReply = 2 | SystemReply = 3 | DirectReplyError = 4 | SystemReplyError = 5</div> <div class="fsdocs-tip" id="321">val request: commands: Command list -&gt; globalSize: uint16 -&gt; brick: Brick -&gt; Async&lt;ReadOnlyMemory&lt;byte&gt;&gt;</div> <div class="fsdocs-tip" id="322">val data: IMemoryOwner&lt;byte&gt;</div> <div class="fsdocs-tip" id="323">member Brick.AsyncRequest: sequence: Sequence * data: ReadOnlyMemory&lt;byte&gt; -&gt; Async&lt;ReadOnlyMemory&lt;byte&gt;&gt;</div> <div class="fsdocs-tip" id="324">val replyType: ReplyType</div> <div class="fsdocs-tip" id="325">property ReadOnlyMemory.Span: ReadOnlySpan&lt;byte&gt; with get<br /><em>&lt;summary&gt;Gets a span from the memory region.&lt;/summary&gt;<br />&lt;returns&gt;A memory span.&lt;/returns&gt;</em></div> <div class="fsdocs-tip" id="326">ReplyType.DirectReplyError: ReplyType = 4</div> <div class="fsdocs-tip" id="327">ReplyType.SystemReplyError: ReplyType = 5</div> <div class="fsdocs-tip" id="328">val failwith: message: string -&gt; &#39;T</div> <div class="fsdocs-tip" id="329">val readLength: &#39;a * dataType: ReadDataType * &#39;b -&gt; int</div> <div class="fsdocs-tip" id="330">val readAux: brick: Brick -&gt; inputs: (InputPort * ReadDataType * Mode) list -&gt; Async&lt;Map&lt;(InputPort * ReadDataType * Mode),ReadOnlyMemory&lt;byte&gt;&gt;&gt;</div> <div class="fsdocs-tip" id="331">val inputs: (InputPort * ReadDataType * Mode) list</div> <div class="fsdocs-tip" id="332">val isEmpty: list: &#39;T list -&gt; bool</div> <div class="fsdocs-tip" id="333">val globalSize: int</div> <div class="fsdocs-tip" id="334">val mapFold&lt;&#39;T,&#39;State,&#39;Result&gt; : mapping: (&#39;State -&gt; &#39;T -&gt; &#39;Result * &#39;State) -&gt; state: &#39;State -&gt; list: &#39;T list -&gt; &#39;Result list * &#39;State</div> <div class="fsdocs-tip" id="335">val offset: int</div> <div class="fsdocs-tip" id="336">val input: InputPort * ReadDataType * Mode</div> <div class="fsdocs-tip" id="337">val sensorsData: ReadOnlyMemory&lt;byte&gt;</div> <div class="fsdocs-tip" id="338">ReadOnlyMemory.Slice(start: int) : ReadOnlyMemory&lt;byte&gt;<br />ReadOnlyMemory.Slice(start: int, length: int) : ReadOnlyMemory&lt;byte&gt;</div> <div class="fsdocs-tip" id="339">val response: Map&lt;(InputPort * ReadDataType * Mode),ReadOnlyMemory&lt;byte&gt;&gt;</div> <div class="fsdocs-tip" id="340">val fst: tuple: (&#39;T1 * &#39;T2) -&gt; &#39;T1</div> <div class="fsdocs-tip" id="341">val ofList: elements: (&#39;Key * &#39;T) list -&gt; Map&lt;&#39;Key,&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="342">type InputRequest = InputPort * ReadDataType * Mode</div> <div class="fsdocs-tip" id="343">type Sensor&lt;&#39;t&gt; = { Inputs: Set&lt;InputRequest&gt; Get: (Map&lt;InputRequest,ReadOnlyMemory&lt;byte&gt;&gt; -&gt; &#39;t) }</div> <div class="fsdocs-tip" id="344">Multiple items<br />module Set from Microsoft.FSharp.Collections<br /><br />--------------------<br />type Set&lt;&#39;T (requires comparison)&gt; = interface IReadOnlyCollection&lt;&#39;T&gt; interface IStructuralEquatable interface IComparable interface IEnumerable interface IEnumerable&lt;&#39;T&gt; interface ICollection&lt;&#39;T&gt; new: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt; member Add: value: &#39;T -&gt; Set&lt;&#39;T&gt; member Contains: value: &#39;T -&gt; bool override Equals: objnull -&gt; bool ...<br /><br />--------------------<br />new: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="345">val input: InputPort * ReadDataType * Mode -&gt; Sensor&lt;ReadOnlyMemory&lt;byte&gt;&gt;</div> <div class="fsdocs-tip" id="346">val req: InputRequest</div> <div class="fsdocs-tip" id="347">val singleton: value: &#39;T -&gt; Set&lt;&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="348">val m: Map&lt;InputRequest,ReadOnlyMemory&lt;byte&gt;&gt;</div> <div class="fsdocs-tip" id="349">val read: sensor: Sensor&lt;&#39;t&gt; -&gt; brick: Brick -&gt; Async&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="350">val sensor: Sensor&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="351">val inputs: InputRequest list</div> <div class="fsdocs-tip" id="352">val toList: set: Set&lt;&#39;T&gt; -&gt; &#39;T list (requires comparison)</div> <div class="fsdocs-tip" id="353">Sensor.Inputs: Set&lt;InputRequest&gt;</div> <div class="fsdocs-tip" id="354">Sensor.Get: Map&lt;InputRequest,ReadOnlyMemory&lt;byte&gt;&gt; -&gt; &#39;t</div> <div class="fsdocs-tip" id="355">val ret: x: &#39;a -&gt; Sensor&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="356">val empty&lt;&#39;T (requires comparison)&gt; : Set&lt;&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="357">val map: f: (&#39;a -&gt; &#39;b) -&gt; s: Sensor&lt;&#39;a&gt; -&gt; Sensor&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="358">val f: (&#39;a -&gt; &#39;b)</div> <div class="fsdocs-tip" id="359">val s: Sensor&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="360">Sensor.Get: Map&lt;InputRequest,ReadOnlyMemory&lt;byte&gt;&gt; -&gt; &#39;a</div> <div class="fsdocs-tip" id="361">val map2: f: (&#39;a -&gt; &#39;b -&gt; &#39;c) -&gt; sx: Sensor&lt;&#39;a&gt; -&gt; sy: Sensor&lt;&#39;b&gt; -&gt; Sensor&lt;&#39;c&gt;</div> <div class="fsdocs-tip" id="362">val f: (&#39;a -&gt; &#39;b -&gt; &#39;c)</div> <div class="fsdocs-tip" id="363">val sx: Sensor&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="364">val sy: Sensor&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="365">val y: &#39;b</div> <div class="fsdocs-tip" id="366">Sensor.Get: Map&lt;InputRequest,ReadOnlyMemory&lt;byte&gt;&gt; -&gt; &#39;b</div> <div class="fsdocs-tip" id="367">val zip: sx: Sensor&lt;&#39;a&gt; -&gt; sy: Sensor&lt;&#39;b&gt; -&gt; Sensor&lt;&#39;a * &#39;b&gt;</div> <div class="fsdocs-tip" id="368">val apply: sf: Sensor&lt;(&#39;a -&gt; &#39;b)&gt; -&gt; sx: Sensor&lt;&#39;a&gt; -&gt; Sensor&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="369">val sf: Sensor&lt;(&#39;a -&gt; &#39;b)&gt;</div> <div class="fsdocs-tip" id="370">val typedInput: dataType: ReadDataType -&gt; convert: (ReadOnlyMemory&lt;byte&gt; -&gt; &#39;a) -&gt; port: InputPort -&gt; mode: Mode -&gt; Sensor&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="371">val convert: (ReadOnlyMemory&lt;byte&gt; -&gt; &#39;a)</div> <div class="fsdocs-tip" id="372">val port: InputPort</div> <div class="fsdocs-tip" id="373">val inputSi: (InputPort -&gt; Mode -&gt; Sensor&lt;float32&gt;)</div> <div class="fsdocs-tip" id="374">BitConverter.ToSingle(value: ReadOnlySpan&lt;byte&gt;) : float32<br />BitConverter.ToSingle(value: byte array, startIndex: int) : float32</div> <div class="fsdocs-tip" id="375">val inputRaw: (InputPort -&gt; Mode -&gt; Sensor&lt;int&gt;)</div> <div class="fsdocs-tip" id="376">BitConverter.ToInt32(value: ReadOnlySpan&lt;byte&gt;) : int<br />BitConverter.ToInt32(value: byte array, startIndex: int) : int</div> <div class="fsdocs-tip" id="377">val inputPct: (InputPort -&gt; Mode -&gt; Sensor&lt;int&gt;)</div> <div class="fsdocs-tip" id="378">val inputRgb: (InputPort -&gt; Mode -&gt; Sensor&lt;int * int * int&gt;)</div> <div class="fsdocs-tip" id="379">val span: ReadOnlySpan&lt;byte&gt;</div> <div class="fsdocs-tip" id="380">val r: uint16</div> <div class="fsdocs-tip" id="381">val g: uint16</div> <div class="fsdocs-tip" id="382">ReadOnlySpan.Slice(start: int) : ReadOnlySpan&lt;byte&gt;<br />ReadOnlySpan.Slice(start: int, length: int) : ReadOnlySpan&lt;byte&gt;</div> <div class="fsdocs-tip" id="383">val b: uint16</div> <div class="fsdocs-tip" id="384">type ButtonState = | Pushed | Released</div> <div class="fsdocs-tip" id="385">Multiple items<br />union case ColorMode.Color: ColorMode<br /><br />--------------------<br />type Color = | Transparent | Black | Blue | Green | Yellow | Red | White | Brown</div> <div class="fsdocs-tip" id="386">val reflective: port: InputPort -&gt; Sensor&lt;int&gt;</div> <div class="fsdocs-tip" id="387">val ambient: port: InputPort -&gt; Sensor&lt;int&gt;</div> <div class="fsdocs-tip" id="388">val color: port: InputPort -&gt; Sensor&lt;Color&gt;</div> <div class="fsdocs-tip" id="389">union case Color.Black: Color</div> <div class="fsdocs-tip" id="390">union case Color.Blue: Color</div> <div class="fsdocs-tip" id="391">union case Color.Green: Color</div> <div class="fsdocs-tip" id="392">union case Color.Yellow: Color</div> <div class="fsdocs-tip" id="393">union case Color.Red: Color</div> <div class="fsdocs-tip" id="394">union case Color.White: Color</div> <div class="fsdocs-tip" id="395">union case Color.Brown: Color</div> <div class="fsdocs-tip" id="396">union case Color.Transparent: Color</div> <div class="fsdocs-tip" id="397">val rgb: port: InputPort -&gt; Sensor&lt;int * int * int&gt;</div> <div class="fsdocs-tip" id="398">val proximity: port: InputPort -&gt; Sensor&lt;int&gt;</div> <div class="fsdocs-tip" id="399">val button: port: InputPort -&gt; Sensor&lt;ButtonState&gt;</div> <div class="fsdocs-tip" id="400">union case ButtonState.Pushed: ButtonState</div> <div class="fsdocs-tip" id="401">union case ButtonState.Released: ButtonState</div> <div class="fsdocs-tip" id="402">val isRed: port: InputPort -&gt; Sensor&lt;bool&gt;</div> <div class="fsdocs-tip" id="403">type bool = Boolean</div> <div class="fsdocs-tip" id="404">val c: Color</div> <div class="fsdocs-tip" id="405">module Sensors from 2020-12-03-applicative-computation-expressions-3</div> <div class="fsdocs-tip" id="406">module Color from 2020-12-03-applicative-computation-expressions-3.Sensors</div> <div class="fsdocs-tip" id="407">val colorAndProximityIfPushed: Sensor&lt;(Color * int) option&gt;</div> <div class="fsdocs-tip" id="408">type &#39;T option = Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="409">val color: Color</div> <div class="fsdocs-tip" id="410">val proximity: int</div> <div class="fsdocs-tip" id="411">val button: ButtonState</div> <div class="fsdocs-tip" id="412">module IR from 2020-12-03-applicative-computation-expressions-3.Sensors</div> <div class="fsdocs-tip" id="413">module Touch from 2020-12-03-applicative-computation-expressions-3.Sensors</div> <div class="fsdocs-tip" id="414">Multiple items<br />type SensorBuilder = new: unit -&gt; SensorBuilder member Bind2Return: x: Sensor&lt;&#39;a&gt; * y: Sensor&lt;&#39;b&gt; * f: (&#39;a * &#39;b -&gt; &#39;c) -&gt; Sensor&lt;&#39;c&gt; member BindReturn: x: Sensor&lt;&#39;a&gt; * f: (&#39;a -&gt; &#39;b) -&gt; Sensor&lt;&#39;b&gt; member MergeSources: x: Sensor&lt;&#39;a&gt; * y: Sensor&lt;&#39;b&gt; -&gt; Sensor&lt;&#39;a * &#39;b&gt; member Return: x: &#39;a -&gt; Sensor&lt;&#39;a&gt;<br /><br />--------------------<br />new: unit -&gt; SensorBuilder</div> <div class="fsdocs-tip" id="415">val x: Sensor&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="416">val y: Sensor&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="417">val f: (&#39;a * &#39;b -&gt; &#39;c)</div> <div class="fsdocs-tip" id="418">&#39;c</div> <div class="fsdocs-tip" id="419">val sensor: SensorBuilder</div> <div class="fsdocs-tip" id="420">val colorWhenPushed: Sensor&lt;(Color * int) option&gt;</div> <div class="fsdocs-tip" id="421">val sample2: unit -&gt; unit</div> <div class="fsdocs-tip" id="422">val value: ((int * int * int) * int) option</div> <div class="fsdocs-tip" id="423">val color: int * int * int</div> <div class="fsdocs-tip" id="424">module Raw from 2020-12-03-applicative-computation-expressions-3.Sensors.Color</div> <div class="fsdocs-tip" id="425">val b: ButtonState</div> <div class="fsdocs-tip" id="426">val prox: int</div> <div class="fsdocs-tip" id="427">val printfn: format: Printf.TextWriterFormat&lt;&#39;T&gt; -&gt; &#39;T</div> Applicative Computation Expressions - 2 urn:md5:ac8918be3c934084b9 327bbe245d47c 2020-10-08T08:18:10.7839774+00:00 Jérémie Chassaing <p>In <a href="/post/2020/10/07/applicative-computation-expressions">the last post</a> we used <code>BindReturn</code>and <code>MergeSources</code> to implement the applicative. The advantage of implementing them is that it will work for any number of <code>and!</code>.</p> <p>When using <code>let!</code> with a single <code>and!</code>, it makes one call to <code>MergeSources</code> to pair arguments and one call to <code>BindReturn</code> to pass values to the function.</p> <p>When using <code>let!</code> with two <code>and!</code>, it makes two calls to <code>MergeSources</code> to tuple arguments and one call to <code>BindReturn</code> to pass values to the function.</p> <p>This can be expensive, so you can provide specific implementations for given numbers of parameters to reduce the number of calls.</p> <p>For two arguments, you can implement <code>Bind2Return</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '25', 47)" onmouseover="showTip(event, '25', 47)" class="rt">AsyncBuilder</span> <span class="k">with</span> <span class="k">member</span> <span onmouseout="hideTip(event, '26', 48)" onmouseover="showTip(event, '26', 48)" class="fn">this</span><span class="pn">.</span><span class="fn">Bind2Return</span><span class="pn">(</span><span onmouseout="hideTip(event, '27', 49)" onmouseover="showTip(event, '27', 49)" class="fn">x</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '28', 50)" onmouseover="showTip(event, '28', 50)" class="id">a</span> <span onmouseout="hideTip(event, '29', 51)" onmouseover="showTip(event, '29', 51)" class="rt">Async</span><span class="pn">,</span><span onmouseout="hideTip(event, '30', 52)" onmouseover="showTip(event, '30', 52)" class="fn">y</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '31', 53)" onmouseover="showTip(event, '31', 53)" class="id">b</span> <span onmouseout="hideTip(event, '29', 54)" onmouseover="showTip(event, '29', 54)" class="rt">Async</span><span class="pn">,</span><span onmouseout="hideTip(event, '32', 55)" onmouseover="showTip(event, '32', 55)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '28', 56)" onmouseover="showTip(event, '28', 56)" class="id">a</span> <span class="pn">*</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '31', 57)" onmouseover="showTip(event, '31', 57)" class="id">b</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '33', 58)" onmouseover="showTip(event, '33', 58)" class="id">c</span><span class="pn">)</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '33', 59)" onmouseover="showTip(event, '33', 59)" class="id">c</span> <span onmouseout="hideTip(event, '29', 60)" onmouseover="showTip(event, '29', 60)" class="rt">Async</span> <span class="o">=</span> <span onmouseout="hideTip(event, '26', 61)" onmouseover="showTip(event, '26', 61)" class="fn">this</span><span class="pn">.</span><span onmouseout="hideTip(event, '34', 62)" onmouseover="showTip(event, '34', 62)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '29', 63)" onmouseover="showTip(event, '29', 63)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '35', 64)" onmouseover="showTip(event, '35', 64)" class="id">StartChild</span> <span onmouseout="hideTip(event, '27', 65)" onmouseover="showTip(event, '27', 65)" class="fn">x</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '36', 66)" onmouseover="showTip(event, '36', 66)" class="fn">xa</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '26', 67)" onmouseover="showTip(event, '26', 67)" class="fn">this</span><span class="pn">.</span><span onmouseout="hideTip(event, '34', 68)" onmouseover="showTip(event, '34', 68)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '29', 69)" onmouseover="showTip(event, '29', 69)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '35', 70)" onmouseover="showTip(event, '35', 70)" class="id">StartChild</span> <span onmouseout="hideTip(event, '30', 71)" onmouseover="showTip(event, '30', 71)" class="fn">y</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '37', 72)" onmouseover="showTip(event, '37', 72)" class="fn">ya</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '26', 73)" onmouseover="showTip(event, '26', 73)" class="fn">this</span><span class="pn">.</span><span onmouseout="hideTip(event, '34', 74)" onmouseover="showTip(event, '34', 74)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '36', 75)" onmouseover="showTip(event, '36', 75)" class="fn">xa</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '38', 76)" onmouseover="showTip(event, '38', 76)" class="fn">xv</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '26', 77)" onmouseover="showTip(event, '26', 77)" class="fn">this</span><span class="pn">.</span><span onmouseout="hideTip(event, '34', 78)" onmouseover="showTip(event, '34', 78)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '37', 79)" onmouseover="showTip(event, '37', 79)" class="fn">ya</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '39', 80)" onmouseover="showTip(event, '39', 80)" class="fn">yv</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '26', 81)" onmouseover="showTip(event, '26', 81)" class="fn">this</span><span class="pn">.</span><span onmouseout="hideTip(event, '40', 82)" onmouseover="showTip(event, '40', 82)" class="id">Return</span> <span class="pn">(</span><span onmouseout="hideTip(event, '32', 83)" onmouseover="showTip(event, '32', 83)" class="fn">f</span><span class="pn">(</span><span onmouseout="hideTip(event, '38', 84)" onmouseover="showTip(event, '38', 84)" class="fn">xv</span><span class="pn">,</span> <span onmouseout="hideTip(event, '39', 85)" onmouseover="showTip(event, '39', 85)" class="fn">yv</span><span class="pn">)</span><span class="pn">)</span><span class="pn">)</span> <span class="pn">)</span> <span class="pn">)</span> <span class="pn">)</span> </code></pre> <p>its signature is:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="o">*</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> <span class="o">*</span> <span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="o">*</span> <span class="id">&#39;</span><span class="id">b</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">c</span><span class="pn">&gt;</span> </code></pre> <p>Notice that it is similar to <code>map2</code> signature.</p> <p>We can check that it's working as expected:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span onmouseout="hideTip(event, '41', 86)" onmouseover="showTip(event, '41', 86)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '42', 87)" onmouseover="showTip(event, '42', 87)" class="fn">parisCoords</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 88)" onmouseover="showTip(event, '41', 88)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '43', 89)" onmouseover="showTip(event, '43', 89)" class="fn">paris</span> <span class="o">=</span> <span onmouseout="hideTip(event, '4', 90)" onmouseover="showTip(event, '4', 90)" class="rt">ZipCode</span><span class="pn">.</span><span onmouseout="hideTip(event, '44', 91)" onmouseover="showTip(event, '44', 91)" class="id">AsyncLoad</span> <span class="s">&quot;http://api.zippopotam.us/fr/75020&quot;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '21', 92)" onmouseover="showTip(event, '21', 92)" class="fn">coord</span> <span onmouseout="hideTip(event, '43', 93)" onmouseover="showTip(event, '43', 93)" class="fn">paris</span> <span class="pn">}</span> <span class="k">and!</span> <span class="fn">londonCoords</span> <span class="o">=</span> <span onmouseout="hideTip(event, '41', 94)" onmouseover="showTip(event, '41', 94)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '45', 95)" onmouseover="showTip(event, '45', 95)" class="fn">london</span> <span class="o">=</span> <span onmouseout="hideTip(event, '4', 96)" onmouseover="showTip(event, '4', 96)" class="rt">ZipCode</span><span class="pn">.</span><span onmouseout="hideTip(event, '44', 97)" onmouseover="showTip(event, '44', 97)" class="id">AsyncLoad</span> <span class="s">&quot;http://api.zippopotam.us/GB/EC1&quot;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '21', 98)" onmouseover="showTip(event, '21', 98)" class="fn">coord</span> <span onmouseout="hideTip(event, '45', 99)" onmouseover="showTip(event, '45', 99)" class="fn">london</span><span class="pn">}</span> <span class="k">return</span> <span onmouseout="hideTip(event, '6', 100)" onmouseover="showTip(event, '6', 100)" class="fn">dist</span> <span class="fn">parisCoords</span> <span class="fn">londonCoords</span> <span class="pn">}</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '29', 101)" onmouseover="showTip(event, '29', 101)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '46', 102)" onmouseover="showTip(event, '46', 102)" class="id">RunSynchronously</span> </code></pre> <p>To handle a <code>let! and! and!</code> case you have to provide a <code>Bind3Return</code> member that takes 3 values and a function. You can also provide a <code>Bind4Return</code>, <code>Bind5Return</code>... and from my tests there is no limit in the number of arguments you can test. F# would happily call a <code>Bind265Return</code> if it had to.</p> <p>Those additional functions are occasions to optimize the implementation by reducing the number of intermediate allocations and function calls.</p> <p>Obviously, it's advised to provide only a few special cases and fall back to <code>BindReturn</code> and <code>MergeSources</code> for the rest.</p> <p>Other options for implementation is to provide <code>MergeSources3</code>, <code>MergeSources4</code> to reduce the number of intermediate tuples. The signature will be for <code>MergeSources3</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="pn">*</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> <span class="pn">*</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">c</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span> <span class="pn">*</span> <span class="id">&#39;</span><span class="id">b</span> <span class="pn">*</span> <span class="id">&#39;</span><span class="id">c</span><span class="pn">&gt;</span> </code></pre> <p>It's also possible to define <code>Bind2</code>, <code>Bind3</code> with the following signatures:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="pn">*</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> <span class="pn">*</span> <span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="pn">*</span> <span class="id">&#39;</span><span class="id">b</span> <span class="k">-&gt;</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">c</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">c</span><span class="pn">&gt;</span> </code></pre> <p>This looks like the <code>Bind2Return</code> except that the function already returns a wrapped value.</p> <p>You can find the complete documentation in <a href="https://github.com/fsharp/fslang-design/blob/master/preview/FS-1063-support-letbang-andbang-for-applicative-functors.md#detailed-design">the RFC</a></p> <div class="fsdocs-tip" id="1">namespace System</div> <div class="fsdocs-tip" id="2">Multiple items<br />namespace FSharp<br /><br />--------------------<br />namespace Microsoft.FSharp</div> <div class="fsdocs-tip" id="3">Multiple items<br />namespace FSharp.Data<br /><br />--------------------<br />namespace Microsoft.FSharp.Data</div> <div class="fsdocs-tip" id="4">type ZipCode = JsonProvider&lt;...&gt;</div> <div class="fsdocs-tip" id="5">type JsonProvider<br /><em>&lt;summary&gt;Typed representation of a JSON document.&lt;/summary&gt; &lt;param name=&#39;Sample&#39;&gt;Location of a JSON sample file or a string containing a sample JSON document.&lt;/param&gt; &lt;param name=&#39;SampleIsList&#39;&gt;If true, sample should be a list of individual samples for the inference.&lt;/param&gt; &lt;param name=&#39;RootName&#39;&gt;The name to be used to the root type. Defaults to `Root`.&lt;/param&gt; &lt;param name=&#39;Culture&#39;&gt;The culture used for parsing numbers and dates. Defaults to the invariant culture.&lt;/param&gt; &lt;param name=&#39;Encoding&#39;&gt;The encoding used to read the sample. You can specify either the character set name or the codepage number. Defaults to UTF8 for files, and to ISO-8859-1 the for HTTP requests, unless `charset` is specified in the `Content-Type` response header.&lt;/param&gt; &lt;param name=&#39;ResolutionFolder&#39;&gt;A directory that is used when resolving relative file references (at design time and in hosted execution).&lt;/param&gt; &lt;param name=&#39;EmbeddedResource&#39;&gt;When specified, the type provider first attempts to load the sample from the specified resource (e.g. &#39;MyCompany.MyAssembly, resource_name.json&#39;). This is useful when exposing types generated by the type provider.&lt;/param&gt; &lt;param name=&#39;InferTypesFromValues&#39;&gt; This parameter is deprecated. Please use InferenceMode instead. If true, turns on additional type inference from values. (e.g. type inference infers string values such as &quot;123&quot; as ints and values constrained to 0 and 1 as booleans.)&lt;/param&gt; &lt;param name=&#39;PreferDictionaries&#39;&gt;If true, json records are interpreted as dictionaries when the names of all the fields are inferred (by type inference rules) into the same non-string primitive type.&lt;/param&gt; &lt;param name=&#39;InferenceMode&#39;&gt;Possible values: | NoInference -&gt; Inference is disabled. All values are inferred as the most basic type permitted for the value (i.e. string or number or bool). | ValuesOnly -&gt; Types of values are inferred from the Sample. Inline schema support is disabled. This is the default. | ValuesAndInlineSchemasHints -&gt; Types of values are inferred from both values and inline schemas. Inline schemas are special string values that can define a type and/or unit of measure. Supported syntax: typeof&amp;lt;type&amp;gt; or typeof{type} or typeof&amp;lt;type&amp;lt;measure&amp;gt;&amp;gt; or typeof{type{measure}}. Valid measures are the default SI units, and valid types are &lt;c&gt;int&lt;/c&gt;, &lt;c&gt;int64&lt;/c&gt;, &lt;c&gt;bool&lt;/c&gt;, &lt;c&gt;float&lt;/c&gt;, &lt;c&gt;decimal&lt;/c&gt;, &lt;c&gt;date&lt;/c&gt;, &lt;c&gt;datetimeoffset&lt;/c&gt;, &lt;c&gt;timespan&lt;/c&gt;, &lt;c&gt;guid&lt;/c&gt; and &lt;c&gt;string&lt;/c&gt;. | ValuesAndInlineSchemasOverrides -&gt; Same as ValuesAndInlineSchemasHints, but value inferred types are ignored when an inline schema is present. &lt;/param&gt;</em></div> <div class="fsdocs-tip" id="6">val dist: lata: decimal * longa: decimal -&gt; latb: decimal * longb: decimal -&gt; decimal</div> <div class="fsdocs-tip" id="7">val lata: decimal</div> <div class="fsdocs-tip" id="8">Multiple items<br />val decimal: value: &#39;T -&gt; decimal (requires member op_Explicit)<br /><br />--------------------<br />type decimal = Decimal<br /><br />--------------------<br />type decimal&lt;&#39;Measure&gt; = decimal</div> <div class="fsdocs-tip" id="9">val longa: decimal</div> <div class="fsdocs-tip" id="10">val latb: decimal</div> <div class="fsdocs-tip" id="11">val longb: decimal</div> <div class="fsdocs-tip" id="12">val x: float</div> <div class="fsdocs-tip" id="13">Multiple items<br />val float: value: &#39;T -&gt; float (requires member op_Explicit)<br /><br />--------------------<br />type float = Double<br /><br />--------------------<br />type float&lt;&#39;Measure&gt; = float</div> <div class="fsdocs-tip" id="14">val cos: value: &#39;T -&gt; &#39;T (requires member Cos)</div> <div class="fsdocs-tip" id="15">Multiple items<br />val double: value: &#39;T -&gt; double (requires member op_Explicit)<br /><br />--------------------<br />type double = Double<br /><br />--------------------<br />type double&lt;&#39;Measure&gt; = float&lt;&#39;Measure&gt;</div> <div class="fsdocs-tip" id="16">type Math = static member Abs: value: decimal -&gt; decimal + 7 overloads static member Acos: d: float -&gt; float static member Acosh: d: float -&gt; float static member Asin: d: float -&gt; float static member Asinh: d: float -&gt; float static member Atan: d: float -&gt; float static member Atan2: y: float * x: float -&gt; float static member Atanh: d: float -&gt; float static member BigMul: a: int * b: int -&gt; int64 + 5 overloads static member BitDecrement: x: float -&gt; float ...<br /><em>&lt;summary&gt;Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="17">field Math.PI: float = 3.14159265359</div> <div class="fsdocs-tip" id="18">val y: float</div> <div class="fsdocs-tip" id="19">val z: float</div> <div class="fsdocs-tip" id="20">val sqrt: value: &#39;T -&gt; &#39;U (requires member Sqrt)</div> <div class="fsdocs-tip" id="21">val coord: zip: JsonProvider&lt;...&gt;.Root -&gt; decimal * decimal<br /><em>&#160;Gets latitude/longitude for a returned zip info</em></div> <div class="fsdocs-tip" id="22">val zip: JsonProvider&lt;...&gt;.Root</div> <div class="fsdocs-tip" id="23">type Root = inherit IJsonDocument new: postCode: string * country: string * countryAbbreviation: string * places: Placis array -&gt; Root + 1 overload member Country: string member CountryAbbreviation: string member Places: Placis array member PostCode: string</div> <div class="fsdocs-tip" id="24">property JsonProvider&lt;...&gt;.Root.Places: JsonProvider&lt;...&gt;.Placis array with get</div> <div class="fsdocs-tip" id="25">type AsyncBuilder = member Bind: computation: Async&lt;&#39;T&gt; * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt; member Combine: computation1: Async&lt;unit&gt; * computation2: Async&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; member Delay: generator: (unit -&gt; Async&lt;&#39;T&gt;) -&gt; Async&lt;&#39;T&gt; member For: sequence: &#39;T seq * body: (&#39;T -&gt; Async&lt;unit&gt;) -&gt; Async&lt;unit&gt; member Return: value: &#39;T -&gt; Async&lt;&#39;T&gt; member ReturnFrom: computation: Async&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; member TryFinally: computation: Async&lt;&#39;T&gt; * compensation: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; member TryWith: computation: Async&lt;&#39;T&gt; * catchHandler: (exn -&gt; Async&lt;&#39;T&gt;) -&gt; Async&lt;&#39;T&gt; member Using: resource: &#39;T * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt; (requires &#39;T :&gt; IDisposable) member While: guard: (unit -&gt; bool) * computation: Async&lt;unit&gt; -&gt; Async&lt;unit&gt; ...</div> <div class="fsdocs-tip" id="26">val this: AsyncBuilder</div> <div class="fsdocs-tip" id="27">val x: Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="28">&#39;a</div> <div class="fsdocs-tip" id="29">Multiple items<br />type Async = static member AsBeginEnd: computation: (&#39;Arg -&gt; Async&lt;&#39;T&gt;) -&gt; (&#39;Arg * AsyncCallback * objnull -&gt; IAsyncResult) * (IAsyncResult -&gt; &#39;T) * (IAsyncResult -&gt; unit) static member AwaitEvent: event: IEvent&lt;&#39;Del,&#39;T&gt; * ?cancelAction: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; (requires delegate and &#39;Del :&gt; Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -&gt; Async&lt;bool&gt; static member AwaitTask: task: Task&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -&gt; Async&lt;bool&gt; static member CancelDefaultToken: unit -&gt; unit static member Catch: computation: Async&lt;&#39;T&gt; -&gt; Async&lt;Choice&lt;&#39;T,exn&gt;&gt; static member Choice: computations: Async&lt;&#39;T option&gt; seq -&gt; Async&lt;&#39;T option&gt; static member FromBeginEnd: beginAction: (AsyncCallback * objnull -&gt; IAsyncResult) * endAction: (IAsyncResult -&gt; &#39;T) * ?cancelAction: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; + 3 overloads static member FromContinuations: callback: ((&#39;T -&gt; unit) * (exn -&gt; unit) * (OperationCanceledException -&gt; unit) -&gt; unit) -&gt; Async&lt;&#39;T&gt; ...<br /><br />--------------------<br />type Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="30">val y: Async&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="31">&#39;b</div> <div class="fsdocs-tip" id="32">val f: (&#39;a * &#39;b -&gt; &#39;c)</div> <div class="fsdocs-tip" id="33">&#39;c</div> <div class="fsdocs-tip" id="34">member AsyncBuilder.Bind: computation: Async&lt;&#39;T&gt; * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt;</div> <div class="fsdocs-tip" id="35">static member Async.StartChild: computation: Async&lt;&#39;T&gt; * ?millisecondsTimeout: int -&gt; Async&lt;Async&lt;&#39;T&gt;&gt;</div> <div class="fsdocs-tip" id="36">val xa: Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="37">val ya: Async&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="38">val xv: &#39;a</div> <div class="fsdocs-tip" id="39">val yv: &#39;b</div> <div class="fsdocs-tip" id="40">member AsyncBuilder.Return: value: &#39;T -&gt; Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="41">val async: AsyncBuilder</div> <div class="fsdocs-tip" id="42">val parisCoords: decimal * decimal</div> <div class="fsdocs-tip" id="43">val paris: JsonProvider&lt;...&gt;.Root</div> <div class="fsdocs-tip" id="44">JsonProvider&lt;...&gt;.AsyncLoad(uri: string) : Async&lt;JsonProvider&lt;...&gt;.Root&gt;<br /><em>Loads JSON from the specified uri</em></div> <div class="fsdocs-tip" id="45">val london: JsonProvider&lt;...&gt;.Root</div> <div class="fsdocs-tip" id="46">static member Async.RunSynchronously: computation: Async&lt;&#39;T&gt; * ?timeout: int * ?cancellationToken: Threading.CancellationToken -&gt; &#39;T</div> Applicative Computation Expressions urn:md5:de2d64385caec9 83b 940 5f3e89a60 2020-10-07T18:55:59.8453833+00:00 Jérémie Chassaing <p>In <a href="/post/2020/10/03/applicatives-irl">the last post</a> we saw how to implement applicatives using <code>map</code>, <code>map2</code> and <code>apply</code> to define <code>&lt;!&gt;</code> and <code>&lt;*&gt;</code> operators.</p> <p>This time, we will use <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions">Computation Expressions</a> to achieve the same result. <em>This is not yet part of F# 5.0, you need the --langversion:preview flag to compile the following code</em>.</p> <p>Let's start again with our <code>Query&lt;'t&gt;</code> type.</p> <p>As a reminder, we created it to access a service that is called with a list of properties to return for a given document.</p> <p>This is a mock version of such a service. In the real world, you'll call Elastic Search indicating the document id and the properties you need:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '2', 2)" onmouseover="showTip(event, '2', 2)" class="fn">queryService</span> <span class="pn">(</span><span onmouseout="hideTip(event, '3', 3)" onmouseover="showTip(event, '3', 3)" class="fn">properties</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 4)" onmouseover="showTip(event, '4', 4)" class="rt">string</span> <span onmouseout="hideTip(event, '5', 5)" onmouseover="showTip(event, '5', 5)" class="rt">Set</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '6', 6)" onmouseover="showTip(event, '6', 6)" class="rt">Map</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '4', 7)" onmouseover="showTip(event, '4', 7)" class="rt">string</span><span class="pn">,</span><span onmouseout="hideTip(event, '4', 8)" onmouseover="showTip(event, '4', 8)" class="rt">string</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '6', 9)" onmouseover="showTip(event, '6', 9)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '7', 10)" onmouseover="showTip(event, '7', 10)" class="id">ofList</span> <span class="pn">[</span> <span class="k">if</span> <span onmouseout="hideTip(event, '5', 11)" onmouseover="showTip(event, '5', 11)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '8', 12)" onmouseover="showTip(event, '8', 12)" class="id">contains</span> <span class="s">&quot;firstname&quot;</span> <span onmouseout="hideTip(event, '3', 13)" onmouseover="showTip(event, '3', 13)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;firstname&quot;</span><span class="pn">,</span> <span class="s">&quot;John&quot;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '5', 14)" onmouseover="showTip(event, '5', 14)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '8', 15)" onmouseover="showTip(event, '8', 15)" class="id">contains</span> <span class="s">&quot;lastname&quot;</span> <span onmouseout="hideTip(event, '3', 16)" onmouseover="showTip(event, '3', 16)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;lastname&quot;</span><span class="pn">,</span> <span class="s">&quot;Doe&quot;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '5', 17)" onmouseover="showTip(event, '5', 17)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '8', 18)" onmouseover="showTip(event, '8', 18)" class="id">contains</span> <span class="s">&quot;age&quot;</span> <span onmouseout="hideTip(event, '3', 19)" onmouseover="showTip(event, '3', 19)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;age&quot;</span><span class="pn">,</span> <span class="s">&quot;42&quot;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '5', 20)" onmouseover="showTip(event, '5', 20)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '8', 21)" onmouseover="showTip(event, '8', 21)" class="id">contains</span> <span class="s">&quot;favoritelanguage&quot;</span> <span onmouseout="hideTip(event, '3', 22)" onmouseover="showTip(event, '3', 22)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;favoritelanguage&quot;</span><span class="pn">,</span> <span class="s">&quot;F#&quot;</span> <span class="pn">]</span> </code></pre> <p>The problem with this kind of service is that there is usually no way to be sure that all properties used in the result have been correctly requested. This type contains both a list of properties to query from an external service as well as the code using fetched properties to build the result.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '9', 23)" onmouseover="showTip(event, '9', 23)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 24)" onmouseover="showTip(event, '10', 24)" class="id">t</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 25)" onmouseover="showTip(event, '4', 25)" class="rt">string</span> <span onmouseout="hideTip(event, '5', 26)" onmouseover="showTip(event, '5', 26)" class="rt">Set</span> <span class="fn">Get</span><span class="pn">:</span> <span onmouseout="hideTip(event, '6', 27)" onmouseover="showTip(event, '6', 27)" class="rt">Map</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '4', 28)" onmouseover="showTip(event, '4', 28)" class="rt">string</span><span class="pn">,</span><span onmouseout="hideTip(event, '4', 29)" onmouseover="showTip(event, '4', 29)" class="rt">string</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 30)" onmouseover="showTip(event, '10', 30)" class="id">t</span> <span class="pn">}</span> </code></pre> <p>It can be used to call the service:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '11', 31)" onmouseover="showTip(event, '11', 31)" class="fn">callService</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 32)" onmouseover="showTip(event, '12', 32)" class="fn">query</span><span class="pn">:</span> <span onmouseout="hideTip(event, '9', 33)" onmouseover="showTip(event, '9', 33)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 34)" onmouseover="showTip(event, '10', 34)" class="id">t</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 35)" onmouseover="showTip(event, '10', 35)" class="id">t</span> <span class="o">=</span> <span onmouseout="hideTip(event, '2', 36)" onmouseover="showTip(event, '2', 36)" class="fn">queryService</span> <span onmouseout="hideTip(event, '12', 37)" onmouseover="showTip(event, '12', 37)" class="fn">query</span><span class="pn">.</span><span onmouseout="hideTip(event, '13', 38)" onmouseover="showTip(event, '13', 38)" class="id">Properties</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '12', 39)" onmouseover="showTip(event, '12', 39)" class="fn">query</span><span class="pn">.</span><span onmouseout="hideTip(event, '14', 40)" onmouseover="showTip(event, '14', 40)" class="id">Get</span> </code></pre> <p>From here we defined a function to create a query from a single column:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span onmouseout="hideTip(event, '9', 41)" onmouseover="showTip(event, '9', 41)" class="m">Query</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '15', 42)" onmouseover="showTip(event, '15', 42)" class="fn">prop</span> <span onmouseout="hideTip(event, '16', 43)" onmouseover="showTip(event, '16', 43)" class="fn">name</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span> <span class="o">=</span> <span onmouseout="hideTip(event, '5', 44)" onmouseover="showTip(event, '5', 44)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '17', 45)" onmouseover="showTip(event, '17', 45)" class="id">singleton</span> <span onmouseout="hideTip(event, '16', 46)" onmouseover="showTip(event, '16', 46)" class="fn">name</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '18', 47)" onmouseover="showTip(event, '18', 47)" class="fn">m</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '18', 48)" onmouseover="showTip(event, '18', 48)" class="fn">m</span><span class="pn">.</span><span class="pn">[</span><span onmouseout="hideTip(event, '16', 49)" onmouseover="showTip(event, '16', 49)" class="fn">name</span><span class="pn">]</span> <span class="pn">}</span> </code></pre> <p>And the <code>map</code> function that applies a given function to the result.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '19', 50)" onmouseover="showTip(event, '19', 50)" class="fn">map</span> <span onmouseout="hideTip(event, '20', 51)" onmouseover="showTip(event, '20', 51)" class="fn">f</span> <span onmouseout="hideTip(event, '21', 52)" onmouseover="showTip(event, '21', 52)" class="fn">q</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span> <span class="o">=</span> <span onmouseout="hideTip(event, '21', 53)" onmouseover="showTip(event, '21', 53)" class="fn">q</span><span class="pn">.</span><span onmouseout="hideTip(event, '13', 54)" onmouseover="showTip(event, '13', 54)" class="id">Properties</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '18', 55)" onmouseover="showTip(event, '18', 55)" class="fn">m</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '22', 56)" onmouseover="showTip(event, '22', 56)" class="fn">value</span> <span class="o">=</span> <span onmouseout="hideTip(event, '21', 57)" onmouseover="showTip(event, '21', 57)" class="fn">q</span><span class="pn">.</span><span onmouseout="hideTip(event, '23', 58)" onmouseover="showTip(event, '23', 58)" class="id">Get</span> <span onmouseout="hideTip(event, '18', 59)" onmouseover="showTip(event, '18', 59)" class="fn">m</span> <span onmouseout="hideTip(event, '20', 60)" onmouseover="showTip(event, '20', 60)" class="fn">f</span> <span onmouseout="hideTip(event, '22', 61)" onmouseover="showTip(event, '22', 61)" class="fn">value</span> <span class="pn">}</span> </code></pre> <p>We also defined a <code>map2</code> to combine two queries as a single one. This query will request the unions of the argument queries properties, and call the first query to get its result, the second to get the other result, and pass both to the given function to combine them:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '24', 62)" onmouseover="showTip(event, '24', 62)" class="fn">map2</span> <span onmouseout="hideTip(event, '25', 63)" onmouseover="showTip(event, '25', 63)" class="fn">f</span> <span onmouseout="hideTip(event, '26', 64)" onmouseover="showTip(event, '26', 64)" class="fn">x</span> <span onmouseout="hideTip(event, '27', 65)" onmouseover="showTip(event, '27', 65)" class="fn">y</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span> <span class="o">=</span> <span onmouseout="hideTip(event, '26', 66)" onmouseover="showTip(event, '26', 66)" class="fn">x</span><span class="pn">.</span><span onmouseout="hideTip(event, '13', 67)" onmouseover="showTip(event, '13', 67)" class="id">Properties</span> <span class="o">+</span> <span onmouseout="hideTip(event, '27', 68)" onmouseover="showTip(event, '27', 68)" class="fn">y</span><span class="pn">.</span><span onmouseout="hideTip(event, '13', 69)" onmouseover="showTip(event, '13', 69)" class="id">Properties</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '18', 70)" onmouseover="showTip(event, '18', 70)" class="fn">m</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '28', 71)" onmouseover="showTip(event, '28', 71)" class="fn">vx</span> <span class="o">=</span> <span onmouseout="hideTip(event, '26', 72)" onmouseover="showTip(event, '26', 72)" class="fn">x</span><span class="pn">.</span><span onmouseout="hideTip(event, '23', 73)" onmouseover="showTip(event, '23', 73)" class="id">Get</span> <span onmouseout="hideTip(event, '18', 74)" onmouseover="showTip(event, '18', 74)" class="fn">m</span> <span class="k">let</span> <span onmouseout="hideTip(event, '29', 75)" onmouseover="showTip(event, '29', 75)" class="fn">vy</span> <span class="o">=</span> <span onmouseout="hideTip(event, '27', 76)" onmouseover="showTip(event, '27', 76)" class="fn">y</span><span class="pn">.</span><span onmouseout="hideTip(event, '30', 77)" onmouseover="showTip(event, '30', 77)" class="id">Get</span> <span onmouseout="hideTip(event, '18', 78)" onmouseover="showTip(event, '18', 78)" class="fn">m</span> <span onmouseout="hideTip(event, '25', 79)" onmouseover="showTip(event, '25', 79)" class="fn">f</span> <span onmouseout="hideTip(event, '28', 80)" onmouseover="showTip(event, '28', 80)" class="fn">vx</span> <span onmouseout="hideTip(event, '29', 81)" onmouseover="showTip(event, '29', 81)" class="fn">vy</span> <span class="pn">}</span> </code></pre> <p>With <code>map2</code> we can define a <code>zip</code> function that takes two <code>Query</code> arguments and combine their results as a pair. We will use this function in our builder.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '31', 82)" onmouseover="showTip(event, '31', 82)" class="fn">zip</span> <span onmouseout="hideTip(event, '26', 83)" onmouseover="showTip(event, '26', 83)" class="fn">x</span> <span onmouseout="hideTip(event, '27', 84)" onmouseover="showTip(event, '27', 84)" class="fn">y</span> <span class="o">=</span> <span onmouseout="hideTip(event, '24', 85)" onmouseover="showTip(event, '24', 85)" class="fn">map2</span> <span class="pn">(</span><span class="k">fun</span> <span onmouseout="hideTip(event, '28', 86)" onmouseover="showTip(event, '28', 86)" class="fn">vx</span> <span onmouseout="hideTip(event, '29', 87)" onmouseover="showTip(event, '29', 87)" class="fn">vy</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '28', 88)" onmouseover="showTip(event, '28', 88)" class="fn">vx</span><span class="pn">,</span><span onmouseout="hideTip(event, '29', 89)" onmouseover="showTip(event, '29', 89)" class="fn">vy</span><span class="pn">)</span> <span onmouseout="hideTip(event, '26', 90)" onmouseover="showTip(event, '26', 90)" class="fn">x</span> <span onmouseout="hideTip(event, '27', 91)" onmouseover="showTip(event, '27', 91)" class="fn">y</span> </code></pre> <p>Computation Expressions are created using types that implement specific members corresponding to the different operations. For applicatives, we need to implement <code>BindReturn</code> with the following signature:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="o">*</span> <span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> </code></pre> <p>Where <code>M</code> in our case is <code>Query</code>. You should spot that it's the same signature as <code>map</code> (with the function as the second argument).</p> <p>The second one is <code>MergeSources</code> and is used to zip parameter together:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="pn">*</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span class="id">M</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span> <span class="pn">*</span> <span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> </code></pre> <p>Here we will use the <code>zip</code> function we defined before.</p> <p>Here is the builder definition:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '32', 92)" onmouseover="showTip(event, '32', 92)" class="rt">QueryBuilder</span><span class="pn">(</span><span class="pn">)</span> <span class="o">=</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">BindReturn</span><span class="pn">(</span><span onmouseout="hideTip(event, '26', 93)" onmouseover="showTip(event, '26', 93)" class="fn">x</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '33', 94)" onmouseover="showTip(event, '33', 94)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 95)" onmouseover="showTip(event, '34', 95)" class="id">a</span><span class="pn">&gt;</span><span class="pn">,</span><span onmouseout="hideTip(event, '20', 96)" onmouseover="showTip(event, '20', 96)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 97)" onmouseover="showTip(event, '34', 97)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 98)" onmouseover="showTip(event, '35', 98)" class="id">b</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '33', 99)" onmouseover="showTip(event, '33', 99)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 100)" onmouseover="showTip(event, '35', 100)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 101)" onmouseover="showTip(event, '33', 101)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '19', 102)" onmouseover="showTip(event, '19', 102)" class="id">map</span> <span onmouseout="hideTip(event, '20', 103)" onmouseover="showTip(event, '20', 103)" class="fn">f</span> <span onmouseout="hideTip(event, '26', 104)" onmouseover="showTip(event, '26', 104)" class="fn">x</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">MergeSources</span><span class="pn">(</span><span onmouseout="hideTip(event, '26', 105)" onmouseover="showTip(event, '26', 105)" class="fn">x</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '33', 106)" onmouseover="showTip(event, '33', 106)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 107)" onmouseover="showTip(event, '34', 107)" class="id">a</span><span class="pn">&gt;</span><span class="pn">,</span><span onmouseout="hideTip(event, '27', 108)" onmouseover="showTip(event, '27', 108)" class="fn">y</span><span class="pn">:</span> <span onmouseout="hideTip(event, '33', 109)" onmouseover="showTip(event, '33', 109)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 110)" onmouseover="showTip(event, '35', 110)" class="id">b</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '33', 111)" onmouseover="showTip(event, '33', 111)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 112)" onmouseover="showTip(event, '34', 112)" class="id">a</span> <span class="pn">*</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 113)" onmouseover="showTip(event, '35', 113)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 114)" onmouseover="showTip(event, '33', 114)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '31', 115)" onmouseover="showTip(event, '31', 115)" class="id">zip</span> <span onmouseout="hideTip(event, '26', 116)" onmouseover="showTip(event, '26', 116)" class="fn">x</span> <span onmouseout="hideTip(event, '27', 117)" onmouseover="showTip(event, '27', 117)" class="fn">y</span> <span class="k">let</span> <span onmouseout="hideTip(event, '36', 118)" onmouseover="showTip(event, '36', 118)" class="id">query</span> <span class="o">=</span> <span onmouseout="hideTip(event, '32', 119)" onmouseover="showTip(event, '32', 119)" class="fn">QueryBuilder</span><span class="pn">(</span><span class="pn">)</span> </code></pre> <p>For our sample, use define a User and the basic properties defined by the service:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '37', 120)" onmouseover="showTip(event, '37', 120)" class="rt">User</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FullName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 121)" onmouseover="showTip(event, '4', 121)" class="rt">string</span> <span class="prop">Age</span><span class="pn">:</span> <span onmouseout="hideTip(event, '38', 122)" onmouseover="showTip(event, '38', 122)" class="vt">int</span> <span class="prop">FavoriteLanguage</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 123)" onmouseover="showTip(event, '4', 123)" class="rt">string</span><span class="pn">}</span> <span class="k">module</span> <span class="m">Props</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '39', 124)" onmouseover="showTip(event, '39', 124)" class="id">firstname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 125)" onmouseover="showTip(event, '33', 125)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '15', 126)" onmouseover="showTip(event, '15', 126)" class="id">prop</span> <span class="s">&quot;firstname&quot;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '40', 127)" onmouseover="showTip(event, '40', 127)" class="id">lastname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 128)" onmouseover="showTip(event, '33', 128)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '15', 129)" onmouseover="showTip(event, '15', 129)" class="id">prop</span> <span class="s">&quot;lastname&quot;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '41', 130)" onmouseover="showTip(event, '41', 130)" class="id">age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 131)" onmouseover="showTip(event, '33', 131)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '15', 132)" onmouseover="showTip(event, '15', 132)" class="id">prop</span> <span class="s">&quot;age&quot;</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '33', 133)" onmouseover="showTip(event, '33', 133)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '19', 134)" onmouseover="showTip(event, '19', 134)" class="id">map</span> <span onmouseout="hideTip(event, '38', 135)" onmouseover="showTip(event, '38', 135)" class="fn">int</span> <span class="k">let</span> <span onmouseout="hideTip(event, '42', 136)" onmouseover="showTip(event, '42', 136)" class="id">favoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 137)" onmouseover="showTip(event, '33', 137)" class="m">Query</span><span class="pn">.</span><span onmouseout="hideTip(event, '15', 138)" onmouseover="showTip(event, '15', 138)" class="id">prop</span> <span class="s">&quot;favoritelanguage&quot;</span> </code></pre> <p>Is is now possible to use the query computation expression to compute new derived properties. Here we define fullname that queries firstname and lastname and appends them together. When using this derived property, it will request both firstname and lastname properties from the service.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">module</span> <span class="m">DerivedProps</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '43', 139)" onmouseover="showTip(event, '43', 139)" class="id">fullname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 140)" onmouseover="showTip(event, '36', 140)" class="k">query</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '44', 141)" onmouseover="showTip(event, '44', 141)" class="fn">firstname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '45', 142)" onmouseover="showTip(event, '45', 142)" class="m">Props</span><span class="pn">.</span><span onmouseout="hideTip(event, '39', 143)" onmouseover="showTip(event, '39', 143)" class="id">firstname</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '46', 144)" onmouseover="showTip(event, '46', 144)" class="fn">lastname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '45', 145)" onmouseover="showTip(event, '45', 145)" class="m">Props</span><span class="pn">.</span><span onmouseout="hideTip(event, '40', 146)" onmouseover="showTip(event, '40', 146)" class="id">lastname</span> <span class="k">return</span> <span onmouseout="hideTip(event, '44', 147)" onmouseover="showTip(event, '44', 147)" class="fn">firstname</span> <span class="o">+</span> <span class="s">&quot; &quot;</span> <span class="o">+</span> <span onmouseout="hideTip(event, '46', 148)" onmouseover="showTip(event, '46', 148)" class="fn">lastname</span> <span class="pn">}</span> </code></pre> <p>you can notice that we use <code>let!</code> and <code>and!</code> here.</p> <p>The meaning of <code>let!</code> is: Give this name (here firstname) to the value <strong>inside</strong> the structure on the right (the query). Since we have a <code>Query&lt;string&gt;</code> on the right, firstname will be a <code>string</code>.</p> <p>The <code>and!</code> means: and at the same time, give this name to this value <strong>inside</strong> this other structure on the right.</p> <p>This is <em>at the same time</em> extracting both values with zip. The actual code looks like this:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span onmouseout="hideTip(event, '36', 149)" onmouseover="showTip(event, '36', 149)" class="id">query</span><span class="pn">.</span><span onmouseout="hideTip(event, '47', 150)" onmouseover="showTip(event, '47', 150)" class="id">BindReturn</span><span class="pn">(</span> <span onmouseout="hideTip(event, '36', 151)" onmouseover="showTip(event, '36', 151)" class="id">query</span><span class="pn">.</span><span onmouseout="hideTip(event, '48', 152)" onmouseover="showTip(event, '48', 152)" class="id">MergeSources</span><span class="pn">(</span><span onmouseout="hideTip(event, '45', 153)" onmouseover="showTip(event, '45', 153)" class="m">Props</span><span class="pn">.</span><span onmouseout="hideTip(event, '39', 154)" onmouseover="showTip(event, '39', 154)" class="id">firstname</span><span class="pn">,</span> <span onmouseout="hideTip(event, '45', 155)" onmouseover="showTip(event, '45', 155)" class="m">Props</span><span class="pn">.</span><span onmouseout="hideTip(event, '40', 156)" onmouseover="showTip(event, '40', 156)" class="id">lastname</span><span class="pn">)</span><span class="pn">,</span> <span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '44', 157)" onmouseover="showTip(event, '44', 157)" class="fn">firstname</span><span class="pn">,</span> <span onmouseout="hideTip(event, '46', 158)" onmouseover="showTip(event, '46', 158)" class="fn">lastname</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '44', 159)" onmouseover="showTip(event, '44', 159)" class="fn">firstname</span> <span class="o">+</span> <span class="s">&quot; &quot;</span> <span class="o">+</span> <span onmouseout="hideTip(event, '46', 160)" onmouseover="showTip(event, '46', 160)" class="fn">lastname</span><span class="pn">)</span> </code></pre> <p>We can then compose queries further by reusing derived properties inside new queries:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '49', 161)" onmouseover="showTip(event, '49', 161)" class="id">user</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 162)" onmouseover="showTip(event, '36', 162)" class="k">query</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '50', 163)" onmouseover="showTip(event, '50', 163)" class="fn">fullname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '51', 164)" onmouseover="showTip(event, '51', 164)" class="m">DerivedProps</span><span class="pn">.</span><span onmouseout="hideTip(event, '43', 165)" onmouseover="showTip(event, '43', 165)" class="id">fullname</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '52', 166)" onmouseover="showTip(event, '52', 166)" class="fn">age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '45', 167)" onmouseover="showTip(event, '45', 167)" class="m">Props</span><span class="pn">.</span><span onmouseout="hideTip(event, '41', 168)" onmouseover="showTip(event, '41', 168)" class="id">age</span> <span class="k">and!</span> <span onmouseout="hideTip(event, '53', 169)" onmouseover="showTip(event, '53', 169)" class="fn">favoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '45', 170)" onmouseover="showTip(event, '45', 170)" class="m">Props</span><span class="pn">.</span><span onmouseout="hideTip(event, '42', 171)" onmouseover="showTip(event, '42', 171)" class="id">favoriteLanguage</span> <span class="k">return</span> <span class="pn">{</span> <span class="prop">FullName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '50', 172)" onmouseover="showTip(event, '50', 172)" class="fn">fullname</span> <span class="prop">Age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '52', 173)" onmouseover="showTip(event, '52', 173)" class="fn">age</span> <span class="prop">FavoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '53', 174)" onmouseover="showTip(event, '53', 174)" class="fn">favoriteLanguage</span> <span class="pn">}</span> <span class="pn">}</span> <span onmouseout="hideTip(event, '11', 175)" onmouseover="showTip(event, '11', 175)" class="fn">callService</span> <span onmouseout="hideTip(event, '49', 176)" onmouseover="showTip(event, '49', 176)" class="id">user</span> </code></pre> <p>Let's use it for async.</p> <p>We define a <code>BindReturn</code> and a <code>MergeSources</code> member. Using a type extension, it is not advised to use <code>async {}</code> blocks in the implementation because it can go recursive...</p> <p>I still put the equivalent construct as a comment:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">type</span> <span onmouseout="hideTip(event, '54', 177)" onmouseover="showTip(event, '54', 177)" class="rt">AsyncBuilder</span> <span class="k">with</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">BindReturn</span><span class="pn">(</span><span onmouseout="hideTip(event, '55', 178)" onmouseover="showTip(event, '55', 178)" class="fn">x</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 179)" onmouseover="showTip(event, '34', 179)" class="id">a</span> <span onmouseout="hideTip(event, '56', 180)" onmouseover="showTip(event, '56', 180)" class="rt">Async</span><span class="pn">,</span><span onmouseout="hideTip(event, '20', 181)" onmouseover="showTip(event, '20', 181)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 182)" onmouseover="showTip(event, '34', 182)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 183)" onmouseover="showTip(event, '35', 183)" class="id">b</span><span class="pn">)</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 184)" onmouseover="showTip(event, '35', 184)" class="id">b</span> <span onmouseout="hideTip(event, '56', 185)" onmouseover="showTip(event, '56', 185)" class="rt">Async</span> <span class="o">=</span> <span class="c">// this is the same as:</span> <span class="c">// async { return f v }</span> <span onmouseout="hideTip(event, '57', 186)" onmouseover="showTip(event, '57', 186)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '58', 187)" onmouseover="showTip(event, '58', 187)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '55', 188)" onmouseover="showTip(event, '55', 188)" class="fn">x</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '59', 189)" onmouseover="showTip(event, '59', 189)" class="fn">v</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '57', 190)" onmouseover="showTip(event, '57', 190)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '60', 191)" onmouseover="showTip(event, '60', 191)" class="id">Return</span> <span class="pn">(</span><span onmouseout="hideTip(event, '20', 192)" onmouseover="showTip(event, '20', 192)" class="fn">f</span> <span onmouseout="hideTip(event, '59', 193)" onmouseover="showTip(event, '59', 193)" class="fn">v</span><span class="pn">)</span><span class="pn">)</span> <span class="k">member</span> <span class="id">_</span><span class="pn">.</span><span class="fn">MergeSources</span><span class="pn">(</span><span onmouseout="hideTip(event, '55', 194)" onmouseover="showTip(event, '55', 194)" class="fn">x</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 195)" onmouseover="showTip(event, '34', 195)" class="id">a</span> <span onmouseout="hideTip(event, '56', 196)" onmouseover="showTip(event, '56', 196)" class="rt">Async</span><span class="pn">,</span> <span onmouseout="hideTip(event, '61', 197)" onmouseover="showTip(event, '61', 197)" class="fn">y</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 198)" onmouseover="showTip(event, '35', 198)" class="id">b</span> <span onmouseout="hideTip(event, '56', 199)" onmouseover="showTip(event, '56', 199)" class="rt">Async</span><span class="pn">)</span> <span class="pn">:</span> <span class="pn">(</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '34', 200)" onmouseover="showTip(event, '34', 200)" class="id">a</span> <span class="pn">*</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '35', 201)" onmouseover="showTip(event, '35', 201)" class="id">b</span><span class="pn">)</span> <span onmouseout="hideTip(event, '56', 202)" onmouseover="showTip(event, '56', 202)" class="rt">Async</span> <span class="o">=</span> <span class="c">// this is the same as:</span> <span class="c">// async {</span> <span class="c">// let! xa = Async.StartChild x</span> <span class="c">// let! ya = Async.StartChild y</span> <span class="c">// let! xv = xa // wait x value</span> <span class="c">// let! yv = ya // wait y value</span> <span class="c">// return xv, yv // pair values</span> <span class="c">// }</span> <span onmouseout="hideTip(event, '57', 203)" onmouseover="showTip(event, '57', 203)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '58', 204)" onmouseover="showTip(event, '58', 204)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '56', 205)" onmouseover="showTip(event, '56', 205)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '62', 206)" onmouseover="showTip(event, '62', 206)" class="id">StartChild</span> <span onmouseout="hideTip(event, '55', 207)" onmouseover="showTip(event, '55', 207)" class="fn">x</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '63', 208)" onmouseover="showTip(event, '63', 208)" class="fn">xa</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '57', 209)" onmouseover="showTip(event, '57', 209)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '58', 210)" onmouseover="showTip(event, '58', 210)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '56', 211)" onmouseover="showTip(event, '56', 211)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '62', 212)" onmouseover="showTip(event, '62', 212)" class="id">StartChild</span> <span onmouseout="hideTip(event, '61', 213)" onmouseover="showTip(event, '61', 213)" class="fn">y</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '64', 214)" onmouseover="showTip(event, '64', 214)" class="fn">ya</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '57', 215)" onmouseover="showTip(event, '57', 215)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '58', 216)" onmouseover="showTip(event, '58', 216)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '63', 217)" onmouseover="showTip(event, '63', 217)" class="fn">xa</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '65', 218)" onmouseover="showTip(event, '65', 218)" class="fn">xv</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '57', 219)" onmouseover="showTip(event, '57', 219)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '58', 220)" onmouseover="showTip(event, '58', 220)" class="id">Bind</span><span class="pn">(</span><span onmouseout="hideTip(event, '64', 221)" onmouseover="showTip(event, '64', 221)" class="fn">ya</span><span class="pn">,</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '66', 222)" onmouseover="showTip(event, '66', 222)" class="fn">yv</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '57', 223)" onmouseover="showTip(event, '57', 223)" class="id">async</span><span class="pn">.</span><span onmouseout="hideTip(event, '60', 224)" onmouseover="showTip(event, '60', 224)" class="id">Return</span> <span class="pn">(</span><span onmouseout="hideTip(event, '65', 225)" onmouseover="showTip(event, '65', 225)" class="fn">xv</span><span class="pn">,</span><span onmouseout="hideTip(event, '66', 226)" onmouseover="showTip(event, '66', 226)" class="fn">yv</span><span class="pn">)</span> <span class="pn">)</span> <span class="pn">)</span> <span class="pn">)</span> <span class="pn">)</span> </code></pre> <p>The zippopotam.us service returns informations about zip codes. We will use the JsonProvider to load the data asynchronously and parse the result.</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">open</span> <span onmouseout="hideTip(event, '67', 227)" onmouseover="showTip(event, '67', 227)" class="id">FSharp</span><span class="pn">.</span><span onmouseout="hideTip(event, '68', 228)" onmouseover="showTip(event, '68', 228)" class="id">Data</span> <span class="k">type</span> <span onmouseout="hideTip(event, '69', 229)" onmouseover="showTip(event, '69', 229)" class="rt">ZipCode</span> <span class="o">=</span> <span onmouseout="hideTip(event, '67', 230)" onmouseover="showTip(event, '67', 230)" class="id">FSharp</span><span class="pn">.</span><span onmouseout="hideTip(event, '68', 231)" onmouseover="showTip(event, '68', 231)" class="id">Data</span><span class="pn">.</span><span onmouseout="hideTip(event, '70', 232)" onmouseover="showTip(event, '70', 232)" class="id">JsonProvider</span><span class="pn">&lt;</span><span class="s">&quot;http://api.zippopotam.us/GB/EC1&quot;</span><span class="pn">&gt;</span> <span class="c">/// Gets latitude/longitude for a returned zip info</span> <span class="k">let</span> <span onmouseout="hideTip(event, '71', 233)" onmouseover="showTip(event, '71', 233)" class="fn">coord</span> <span class="pn">(</span><span onmouseout="hideTip(event, '72', 234)" onmouseover="showTip(event, '72', 234)" class="fn">zip</span><span class="pn">:</span> <span onmouseout="hideTip(event, '69', 235)" onmouseover="showTip(event, '69', 235)" class="rt">ZipCode</span><span class="pn">.</span><span onmouseout="hideTip(event, '73', 236)" onmouseover="showTip(event, '73', 236)" class="id">Root</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '72', 237)" onmouseover="showTip(event, '72', 237)" class="fn">zip</span><span class="pn">.</span><span onmouseout="hideTip(event, '74', 238)" onmouseover="showTip(event, '74', 238)" class="id">Places</span><span class="pn">.</span><span class="pn">[</span><span class="n">0</span><span class="pn">]</span><span class="pn">.</span><span class="id">Latitude</span><span class="pn">,</span> <span onmouseout="hideTip(event, '72', 239)" onmouseover="showTip(event, '72', 239)" class="fn">zip</span><span class="pn">.</span><span onmouseout="hideTip(event, '74', 240)" onmouseover="showTip(event, '74', 240)" class="id">Places</span><span class="pn">.</span><span class="pn">[</span><span class="n">0</span><span class="pn">]</span><span class="pn">.</span><span class="id">Longitude</span> </code></pre> <p>We use <a href="https://stackoverflow.com/questions/1664799/calculating-distance-between-two-points-using-pythagorean-theorem">The pythagorean theorem</a> to compute the distance given the latitude and longitude of two points:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span onmouseout="hideTip(event, '75', 241)" onmouseover="showTip(event, '75', 241)" class="fn">dist</span> <span class="pn">(</span><span onmouseout="hideTip(event, '76', 242)" onmouseover="showTip(event, '76', 242)" class="fn">lata</span><span class="pn">:</span> <span onmouseout="hideTip(event, '77', 243)" onmouseover="showTip(event, '77', 243)" class="vt">decimal</span><span class="pn">,</span><span onmouseout="hideTip(event, '78', 244)" onmouseover="showTip(event, '78', 244)" class="fn">longa</span><span class="pn">:</span> <span onmouseout="hideTip(event, '77', 245)" onmouseover="showTip(event, '77', 245)" class="vt">decimal</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '79', 246)" onmouseover="showTip(event, '79', 246)" class="fn">latb</span><span class="pn">:</span> <span onmouseout="hideTip(event, '77', 247)" onmouseover="showTip(event, '77', 247)" class="vt">decimal</span><span class="pn">,</span> <span onmouseout="hideTip(event, '80', 248)" onmouseover="showTip(event, '80', 248)" class="fn">longb</span><span class="pn">:</span> <span onmouseout="hideTip(event, '77', 249)" onmouseover="showTip(event, '77', 249)" class="vt">decimal</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '81', 250)" onmouseover="showTip(event, '81', 250)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '82', 251)" onmouseover="showTip(event, '82', 251)" class="fn">float</span> <span class="pn">(</span><span onmouseout="hideTip(event, '80', 252)" onmouseover="showTip(event, '80', 252)" class="fn">longb</span> <span class="o">-</span> <span onmouseout="hideTip(event, '78', 253)" onmouseover="showTip(event, '78', 253)" class="fn">longa</span><span class="pn">)</span> <span class="o">*</span> <span onmouseout="hideTip(event, '83', 254)" onmouseover="showTip(event, '83', 254)" class="fn">cos</span> <span class="pn">(</span><span onmouseout="hideTip(event, '84', 255)" onmouseover="showTip(event, '84', 255)" class="fn">double</span> <span class="pn">(</span><span onmouseout="hideTip(event, '79', 256)" onmouseover="showTip(event, '79', 256)" class="fn">latb</span> <span class="o">+</span> <span onmouseout="hideTip(event, '76', 257)" onmouseover="showTip(event, '76', 257)" class="fn">lata</span><span class="pn">)</span> <span class="o">/</span> <span class="n">2.</span> <span class="o">*</span> <span onmouseout="hideTip(event, '85', 258)" onmouseover="showTip(event, '85', 258)" class="id">Math</span><span class="pn">.</span><span onmouseout="hideTip(event, '86', 259)" onmouseover="showTip(event, '86', 259)" class="id">PI</span> <span class="o">/</span> <span class="n">360.</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '87', 260)" onmouseover="showTip(event, '87', 260)" class="fn">y</span> <span class="o">=</span> <span onmouseout="hideTip(event, '82', 261)" onmouseover="showTip(event, '82', 261)" class="fn">float</span> <span class="pn">(</span><span onmouseout="hideTip(event, '79', 262)" onmouseover="showTip(event, '79', 262)" class="fn">latb</span> <span class="o">-</span> <span onmouseout="hideTip(event, '76', 263)" onmouseover="showTip(event, '76', 263)" class="fn">lata</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '88', 264)" onmouseover="showTip(event, '88', 264)" class="fn">z</span> <span class="o">=</span> <span onmouseout="hideTip(event, '89', 265)" onmouseover="showTip(event, '89', 265)" class="fn">sqrt</span> <span class="pn">(</span><span onmouseout="hideTip(event, '81', 266)" onmouseover="showTip(event, '81', 266)" class="fn">x</span><span class="o">*</span><span onmouseout="hideTip(event, '81', 267)" onmouseover="showTip(event, '81', 267)" class="fn">x</span> <span class="o">+</span> <span onmouseout="hideTip(event, '87', 268)" onmouseover="showTip(event, '87', 268)" class="fn">y</span><span class="o">*</span><span onmouseout="hideTip(event, '87', 269)" onmouseover="showTip(event, '87', 269)" class="fn">y</span><span class="pn">)</span> <span onmouseout="hideTip(event, '88', 270)" onmouseover="showTip(event, '88', 270)" class="fn">z</span> <span class="o">*</span> <span class="n">1.852</span> <span class="o">*</span> <span class="n">60.</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '77', 271)" onmouseover="showTip(event, '77', 271)" class="fn">decimal</span> </code></pre> <p>Now using <code>let!</code> <code>and!</code> we fetch and compute the coordinates of Paris and London in parallel and then use both results to get the distance:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span onmouseout="hideTip(event, '57', 272)" onmouseover="showTip(event, '57', 272)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '90', 273)" onmouseover="showTip(event, '90', 273)" class="fn">parisCoords</span> <span class="o">=</span> <span onmouseout="hideTip(event, '57', 274)" onmouseover="showTip(event, '57', 274)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '91', 275)" onmouseover="showTip(event, '91', 275)" class="fn">paris</span> <span class="o">=</span> <span onmouseout="hideTip(event, '69', 276)" onmouseover="showTip(event, '69', 276)" class="rt">ZipCode</span><span class="pn">.</span><span onmouseout="hideTip(event, '92', 277)" onmouseover="showTip(event, '92', 277)" class="id">AsyncLoad</span> <span class="s">&quot;http://api.zippopotam.us/fr/75020&quot;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '71', 278)" onmouseover="showTip(event, '71', 278)" class="fn">coord</span> <span onmouseout="hideTip(event, '91', 279)" onmouseover="showTip(event, '91', 279)" class="fn">paris</span> <span class="pn">}</span> <span class="k">and!</span> <span class="fn">londonCoords</span> <span class="o">=</span> <span onmouseout="hideTip(event, '57', 280)" onmouseover="showTip(event, '57', 280)" class="k">async</span> <span class="pn">{</span> <span class="k">let!</span> <span onmouseout="hideTip(event, '93', 281)" onmouseover="showTip(event, '93', 281)" class="fn">london</span> <span class="o">=</span> <span onmouseout="hideTip(event, '69', 282)" onmouseover="showTip(event, '69', 282)" class="rt">ZipCode</span><span class="pn">.</span><span onmouseout="hideTip(event, '92', 283)" onmouseover="showTip(event, '92', 283)" class="id">AsyncLoad</span> <span class="s">&quot;http://api.zippopotam.us/GB/EC1&quot;</span> <span class="k">return</span> <span onmouseout="hideTip(event, '71', 284)" onmouseover="showTip(event, '71', 284)" class="fn">coord</span> <span onmouseout="hideTip(event, '93', 285)" onmouseover="showTip(event, '93', 285)" class="fn">london</span> <span class="pn">}</span> <span class="k">return</span> <span onmouseout="hideTip(event, '75', 286)" onmouseover="showTip(event, '75', 286)" class="fn">dist</span> <span class="fn">parisCoords</span> <span class="fn">londonCoords</span> <span class="pn">}</span> <span class="o">|&gt;</span> <span onmouseout="hideTip(event, '56', 287)" onmouseover="showTip(event, '56', 287)" class="rt">Async</span><span class="pn">.</span><span onmouseout="hideTip(event, '94', 288)" onmouseover="showTip(event, '94', 288)" class="id">RunSynchronously</span> </code></pre> <p>It's obviously possible to use both Computation Expressions and the approach with operators from the last post for more fun!</p> <div class="fsdocs-tip" id="1">namespace System</div> <div class="fsdocs-tip" id="2">val queryService: properties: Set&lt;string&gt; -&gt; Map&lt;string,string&gt;</div> <div class="fsdocs-tip" id="3">val properties: Set&lt;string&gt;</div> <div class="fsdocs-tip" id="4">Multiple items<br />val string: value: &#39;T -&gt; string<br /><br />--------------------<br />type string = String</div> <div class="fsdocs-tip" id="5">Multiple items<br />module Set from Microsoft.FSharp.Collections<br /><br />--------------------<br />type Set&lt;&#39;T (requires comparison)&gt; = interface IReadOnlyCollection&lt;&#39;T&gt; interface IStructuralEquatable interface IComparable interface IEnumerable interface IEnumerable&lt;&#39;T&gt; interface ICollection&lt;&#39;T&gt; new: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt; member Add: value: &#39;T -&gt; Set&lt;&#39;T&gt; member Contains: value: &#39;T -&gt; bool override Equals: objnull -&gt; bool ...<br /><br />--------------------<br />new: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="6">Multiple items<br />module Map from Microsoft.FSharp.Collections<br /><br />--------------------<br />type Map&lt;&#39;Key,&#39;Value (requires comparison)&gt; = interface IReadOnlyDictionary&lt;&#39;Key,&#39;Value&gt; interface IReadOnlyCollection&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface ICollection&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface IDictionary&lt;&#39;Key,&#39;Value&gt; new: elements: (&#39;Key * &#39;Value) seq -&gt; Map&lt;&#39;Key,&#39;Value&gt; member Add: key: &#39;Key * value: &#39;Value -&gt; Map&lt;&#39;Key,&#39;Value&gt; ...<br /><br />--------------------<br />new: elements: (&#39;Key * &#39;Value) seq -&gt; Map&lt;&#39;Key,&#39;Value&gt;</div> <div class="fsdocs-tip" id="7">val ofList: elements: (&#39;Key * &#39;T) list -&gt; Map&lt;&#39;Key,&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="8">val contains: element: &#39;T -&gt; set: Set&lt;&#39;T&gt; -&gt; bool (requires comparison)</div> <div class="fsdocs-tip" id="9">type Query&lt;&#39;t&gt; = { Properties: Set&lt;string&gt; Get: (Map&lt;string,string&gt; -&gt; &#39;t) }</div> <div class="fsdocs-tip" id="10">&#39;t</div> <div class="fsdocs-tip" id="11">val callService: query: Query&lt;&#39;t&gt; -&gt; &#39;t</div> <div class="fsdocs-tip" id="12">val query: Query&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="13">Query.Properties: Set&lt;string&gt;</div> <div class="fsdocs-tip" id="14">Query.Get: Map&lt;string,string&gt; -&gt; &#39;t</div> <div class="fsdocs-tip" id="15">val prop: name: string -&gt; Query&lt;string&gt;</div> <div class="fsdocs-tip" id="16">val name: string</div> <div class="fsdocs-tip" id="17">val singleton: value: &#39;T -&gt; Set&lt;&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="18">val m: Map&lt;string,string&gt;</div> <div class="fsdocs-tip" id="19">val map: f: (&#39;a -&gt; &#39;b) -&gt; q: Query&lt;&#39;a&gt; -&gt; Query&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="20">val f: (&#39;a -&gt; &#39;b)</div> <div class="fsdocs-tip" id="21">val q: Query&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="22">val value: &#39;a</div> <div class="fsdocs-tip" id="23">Query.Get: Map&lt;string,string&gt; -&gt; &#39;a</div> <div class="fsdocs-tip" id="24">val map2: f: (&#39;a -&gt; &#39;b -&gt; &#39;c) -&gt; x: Query&lt;&#39;a&gt; -&gt; y: Query&lt;&#39;b&gt; -&gt; Query&lt;&#39;c&gt;</div> <div class="fsdocs-tip" id="25">val f: (&#39;a -&gt; &#39;b -&gt; &#39;c)</div> <div class="fsdocs-tip" id="26">val x: Query&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="27">val y: Query&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="28">val vx: &#39;a</div> <div class="fsdocs-tip" id="29">val vy: &#39;b</div> <div class="fsdocs-tip" id="30">Query.Get: Map&lt;string,string&gt; -&gt; &#39;b</div> <div class="fsdocs-tip" id="31">val zip: x: Query&lt;&#39;a&gt; -&gt; y: Query&lt;&#39;b&gt; -&gt; Query&lt;&#39;a * &#39;b&gt;</div> <div class="fsdocs-tip" id="32">Multiple items<br />type QueryBuilder = new: unit -&gt; QueryBuilder member BindReturn: x: Query&lt;&#39;a&gt; * f: (&#39;a -&gt; &#39;b) -&gt; Query&lt;&#39;b&gt; member MergeSources: x: Query&lt;&#39;a&gt; * y: Query&lt;&#39;b&gt; -&gt; Query&lt;&#39;a * &#39;b&gt;<br /><br />--------------------<br />new: unit -&gt; QueryBuilder</div> <div class="fsdocs-tip" id="33">Multiple items<br />module Query from 2020-10-07-applicative-computation-expressions<br /><br />--------------------<br />type Query&lt;&#39;t&gt; = { Properties: Set&lt;string&gt; Get: (Map&lt;string,string&gt; -&gt; &#39;t) }</div> <div class="fsdocs-tip" id="34">&#39;a</div> <div class="fsdocs-tip" id="35">&#39;b</div> <div class="fsdocs-tip" id="36">val query: QueryBuilder</div> <div class="fsdocs-tip" id="37">type User = { FullName: string Age: int FavoriteLanguage: string }</div> <div class="fsdocs-tip" id="38">Multiple items<br />val int: value: &#39;T -&gt; int (requires member op_Explicit)<br /><br />--------------------<br />type int = int32<br /><br />--------------------<br />type int&lt;&#39;Measure&gt; = int</div> <div class="fsdocs-tip" id="39">val firstname: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="40">val lastname: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="41">val age: Query&lt;int&gt;</div> <div class="fsdocs-tip" id="42">val favoriteLanguage: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="43">val fullname: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="44">val firstname: string</div> <div class="fsdocs-tip" id="45">module Props from 2020-10-07-applicative-computation-expressions</div> <div class="fsdocs-tip" id="46">val lastname: string</div> <div class="fsdocs-tip" id="47">member QueryBuilder.BindReturn: x: Query&lt;&#39;a&gt; * f: (&#39;a -&gt; &#39;b) -&gt; Query&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="48">member QueryBuilder.MergeSources: x: Query&lt;&#39;a&gt; * y: Query&lt;&#39;b&gt; -&gt; Query&lt;&#39;a * &#39;b&gt;</div> <div class="fsdocs-tip" id="49">val user: Query&lt;User&gt;</div> <div class="fsdocs-tip" id="50">val fullname: string</div> <div class="fsdocs-tip" id="51">module DerivedProps from 2020-10-07-applicative-computation-expressions</div> <div class="fsdocs-tip" id="52">val age: int</div> <div class="fsdocs-tip" id="53">val favoriteLanguage: string</div> <div class="fsdocs-tip" id="54">type AsyncBuilder = member Bind: computation: Async&lt;&#39;T&gt; * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt; member Combine: computation1: Async&lt;unit&gt; * computation2: Async&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; member Delay: generator: (unit -&gt; Async&lt;&#39;T&gt;) -&gt; Async&lt;&#39;T&gt; member For: sequence: &#39;T seq * body: (&#39;T -&gt; Async&lt;unit&gt;) -&gt; Async&lt;unit&gt; member Return: value: &#39;T -&gt; Async&lt;&#39;T&gt; member ReturnFrom: computation: Async&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; member TryFinally: computation: Async&lt;&#39;T&gt; * compensation: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; member TryWith: computation: Async&lt;&#39;T&gt; * catchHandler: (exn -&gt; Async&lt;&#39;T&gt;) -&gt; Async&lt;&#39;T&gt; member Using: resource: &#39;T * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt; (requires &#39;T :&gt; IDisposable) member While: guard: (unit -&gt; bool) * computation: Async&lt;unit&gt; -&gt; Async&lt;unit&gt; ...</div> <div class="fsdocs-tip" id="55">val x: Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="56">Multiple items<br />type Async = static member AsBeginEnd: computation: (&#39;Arg -&gt; Async&lt;&#39;T&gt;) -&gt; (&#39;Arg * AsyncCallback * objnull -&gt; IAsyncResult) * (IAsyncResult -&gt; &#39;T) * (IAsyncResult -&gt; unit) static member AwaitEvent: event: IEvent&lt;&#39;Del,&#39;T&gt; * ?cancelAction: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; (requires delegate and &#39;Del :&gt; Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -&gt; Async&lt;bool&gt; static member AwaitTask: task: Task&lt;&#39;T&gt; -&gt; Async&lt;&#39;T&gt; + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -&gt; Async&lt;bool&gt; static member CancelDefaultToken: unit -&gt; unit static member Catch: computation: Async&lt;&#39;T&gt; -&gt; Async&lt;Choice&lt;&#39;T,exn&gt;&gt; static member Choice: computations: Async&lt;&#39;T option&gt; seq -&gt; Async&lt;&#39;T option&gt; static member FromBeginEnd: beginAction: (AsyncCallback * objnull -&gt; IAsyncResult) * endAction: (IAsyncResult -&gt; &#39;T) * ?cancelAction: (unit -&gt; unit) -&gt; Async&lt;&#39;T&gt; + 3 overloads static member FromContinuations: callback: ((&#39;T -&gt; unit) * (exn -&gt; unit) * (OperationCanceledException -&gt; unit) -&gt; unit) -&gt; Async&lt;&#39;T&gt; ...<br /><br />--------------------<br />type Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="57">val async: AsyncBuilder</div> <div class="fsdocs-tip" id="58">member AsyncBuilder.Bind: computation: Async&lt;&#39;T&gt; * binder: (&#39;T -&gt; Async&lt;&#39;U&gt;) -&gt; Async&lt;&#39;U&gt;</div> <div class="fsdocs-tip" id="59">val v: &#39;a</div> <div class="fsdocs-tip" id="60">member AsyncBuilder.Return: value: &#39;T -&gt; Async&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="61">val y: Async&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="62">static member Async.StartChild: computation: Async&lt;&#39;T&gt; * ?millisecondsTimeout: int -&gt; Async&lt;Async&lt;&#39;T&gt;&gt;</div> <div class="fsdocs-tip" id="63">val xa: Async&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="64">val ya: Async&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="65">val xv: &#39;a</div> <div class="fsdocs-tip" id="66">val yv: &#39;b</div> <div class="fsdocs-tip" id="67">Multiple items<br />namespace FSharp<br /><br />--------------------<br />namespace Microsoft.FSharp</div> <div class="fsdocs-tip" id="68">Multiple items<br />namespace FSharp.Data<br /><br />--------------------<br />namespace Microsoft.FSharp.Data</div> <div class="fsdocs-tip" id="69">type ZipCode = JsonProvider&lt;...&gt;</div> <div class="fsdocs-tip" id="70">type JsonProvider<br /><em>&lt;summary&gt;Typed representation of a JSON document.&lt;/summary&gt; &lt;param name=&#39;Sample&#39;&gt;Location of a JSON sample file or a string containing a sample JSON document.&lt;/param&gt; &lt;param name=&#39;SampleIsList&#39;&gt;If true, sample should be a list of individual samples for the inference.&lt;/param&gt; &lt;param name=&#39;RootName&#39;&gt;The name to be used to the root type. Defaults to `Root`.&lt;/param&gt; &lt;param name=&#39;Culture&#39;&gt;The culture used for parsing numbers and dates. Defaults to the invariant culture.&lt;/param&gt; &lt;param name=&#39;Encoding&#39;&gt;The encoding used to read the sample. You can specify either the character set name or the codepage number. Defaults to UTF8 for files, and to ISO-8859-1 the for HTTP requests, unless `charset` is specified in the `Content-Type` response header.&lt;/param&gt; &lt;param name=&#39;ResolutionFolder&#39;&gt;A directory that is used when resolving relative file references (at design time and in hosted execution).&lt;/param&gt; &lt;param name=&#39;EmbeddedResource&#39;&gt;When specified, the type provider first attempts to load the sample from the specified resource (e.g. &#39;MyCompany.MyAssembly, resource_name.json&#39;). This is useful when exposing types generated by the type provider.&lt;/param&gt; &lt;param name=&#39;InferTypesFromValues&#39;&gt; This parameter is deprecated. Please use InferenceMode instead. If true, turns on additional type inference from values. (e.g. type inference infers string values such as &quot;123&quot; as ints and values constrained to 0 and 1 as booleans.)&lt;/param&gt; &lt;param name=&#39;PreferDictionaries&#39;&gt;If true, json records are interpreted as dictionaries when the names of all the fields are inferred (by type inference rules) into the same non-string primitive type.&lt;/param&gt; &lt;param name=&#39;InferenceMode&#39;&gt;Possible values: | NoInference -&gt; Inference is disabled. All values are inferred as the most basic type permitted for the value (i.e. string or number or bool). | ValuesOnly -&gt; Types of values are inferred from the Sample. Inline schema support is disabled. This is the default. | ValuesAndInlineSchemasHints -&gt; Types of values are inferred from both values and inline schemas. Inline schemas are special string values that can define a type and/or unit of measure. Supported syntax: typeof&amp;lt;type&amp;gt; or typeof{type} or typeof&amp;lt;type&amp;lt;measure&amp;gt;&amp;gt; or typeof{type{measure}}. Valid measures are the default SI units, and valid types are &lt;c&gt;int&lt;/c&gt;, &lt;c&gt;int64&lt;/c&gt;, &lt;c&gt;bool&lt;/c&gt;, &lt;c&gt;float&lt;/c&gt;, &lt;c&gt;decimal&lt;/c&gt;, &lt;c&gt;date&lt;/c&gt;, &lt;c&gt;datetimeoffset&lt;/c&gt;, &lt;c&gt;timespan&lt;/c&gt;, &lt;c&gt;guid&lt;/c&gt; and &lt;c&gt;string&lt;/c&gt;. | ValuesAndInlineSchemasOverrides -&gt; Same as ValuesAndInlineSchemasHints, but value inferred types are ignored when an inline schema is present. &lt;/param&gt;</em></div> <div class="fsdocs-tip" id="71">val coord: zip: JsonProvider&lt;...&gt;.Root -&gt; decimal * decimal<br /><em>&#160;Gets latitude/longitude for a returned zip info</em></div> <div class="fsdocs-tip" id="72">val zip: JsonProvider&lt;...&gt;.Root</div> <div class="fsdocs-tip" id="73">type Root = inherit IJsonDocument new: postCode: string * country: string * countryAbbreviation: string * places: Placis array -&gt; Root + 1 overload member Country: string member CountryAbbreviation: string member Places: Placis array member PostCode: string</div> <div class="fsdocs-tip" id="74">property JsonProvider&lt;...&gt;.Root.Places: JsonProvider&lt;...&gt;.Placis array with get</div> <div class="fsdocs-tip" id="75">val dist: lata: decimal * longa: decimal -&gt; latb: decimal * longb: decimal -&gt; decimal</div> <div class="fsdocs-tip" id="76">val lata: decimal</div> <div class="fsdocs-tip" id="77">Multiple items<br />val decimal: value: &#39;T -&gt; decimal (requires member op_Explicit)<br /><br />--------------------<br />type decimal = Decimal<br /><br />--------------------<br />type decimal&lt;&#39;Measure&gt; = decimal</div> <div class="fsdocs-tip" id="78">val longa: decimal</div> <div class="fsdocs-tip" id="79">val latb: decimal</div> <div class="fsdocs-tip" id="80">val longb: decimal</div> <div class="fsdocs-tip" id="81">val x: float</div> <div class="fsdocs-tip" id="82">Multiple items<br />val float: value: &#39;T -&gt; float (requires member op_Explicit)<br /><br />--------------------<br />type float = Double<br /><br />--------------------<br />type float&lt;&#39;Measure&gt; = float</div> <div class="fsdocs-tip" id="83">val cos: value: &#39;T -&gt; &#39;T (requires member Cos)</div> <div class="fsdocs-tip" id="84">Multiple items<br />val double: value: &#39;T -&gt; double (requires member op_Explicit)<br /><br />--------------------<br />type double = Double<br /><br />--------------------<br />type double&lt;&#39;Measure&gt; = float&lt;&#39;Measure&gt;</div> <div class="fsdocs-tip" id="85">type Math = static member Abs: value: decimal -&gt; decimal + 7 overloads static member Acos: d: float -&gt; float static member Acosh: d: float -&gt; float static member Asin: d: float -&gt; float static member Asinh: d: float -&gt; float static member Atan: d: float -&gt; float static member Atan2: y: float * x: float -&gt; float static member Atanh: d: float -&gt; float static member BigMul: a: int * b: int -&gt; int64 + 5 overloads static member BitDecrement: x: float -&gt; float ...<br /><em>&lt;summary&gt;Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="86">field Math.PI: float = 3.14159265359</div> <div class="fsdocs-tip" id="87">val y: float</div> <div class="fsdocs-tip" id="88">val z: float</div> <div class="fsdocs-tip" id="89">val sqrt: value: &#39;T -&gt; &#39;U (requires member Sqrt)</div> <div class="fsdocs-tip" id="90">val parisCoords: decimal * decimal</div> <div class="fsdocs-tip" id="91">val paris: JsonProvider&lt;...&gt;.Root</div> <div class="fsdocs-tip" id="92">JsonProvider&lt;...&gt;.AsyncLoad(uri: string) : Async&lt;JsonProvider&lt;...&gt;.Root&gt;<br /><em>Loads JSON from the specified uri</em></div> <div class="fsdocs-tip" id="93">val london: JsonProvider&lt;...&gt;.Root</div> <div class="fsdocs-tip" id="94">static member Async.RunSynchronously: computation: Async&lt;&#39;T&gt; * ?timeout: int * ?cancellationToken: Threading.CancellationToken -&gt; &#39;T</div> Applicatives IRL urn:md5:5c6f65b8e68d48f84de1569851eb54e8 2020-10-03T16:33:28.5620501+00:00 Jérémie Chassaing <p><em>This is the content of the presentation of the same name I did at Open FSharp (San Francisco) and NewCrafts (Paris)</em></p> <p>Monads are all the rage in FP land... but Applicatives are also very useful and quite easy to get. We'll go through 3 real use cases to discover what they're up to.</p> <p>Examples will be in F#. This is of course applicable in other languages with <a href="https://en.wikipedia.org/wiki/Currying">currying</a>.</p> <h2><a name="Options" class="anchor" href="#Options">Options</a></h2> <p>We start with a simple structure: <code>Option&lt;'t&gt;</code>. As a reminder, its definition is</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '4', 6)" onmouseover="showTip(event, '4', 6)" class="rt">Option</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '5', 7)" onmouseover="showTip(event, '5', 7)" class="id">t</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '6', 8)" onmouseover="showTip(event, '6', 8)" class="uc">Some</span> <span class="k">of</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '5', 9)" onmouseover="showTip(event, '5', 9)" class="id">t</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '7', 10)" onmouseover="showTip(event, '7', 10)" class="uc">None</span> </code></pre> <p>It's a value that either contains a value of type <code>'t</code> (the <code>Some</code> case) or doesn't contain a value (<code>None</code>)</p> <h3><a name="map" class="anchor" href="#map">map</a></h3> <p>We can easily write a <code>map</code> function for this structure.</p> <p><code>map</code> takes a <code>'a -&gt; 'b</code> function and applies it to the inner value of the option if any. If the option is <code>None</code>, it simply returns <code>None</code>.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '8', 11)" onmouseover="showTip(event, '8', 11)" class="fn">map</span> <span class="pn">(</span><span onmouseout="hideTip(event, '2', 12)" onmouseover="showTip(event, '2', 12)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 13)" onmouseover="showTip(event, '9', 13)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 14)" onmouseover="showTip(event, '10', 14)" class="id">b</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '11', 15)" onmouseover="showTip(event, '11', 15)" class="fn">x</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 16)" onmouseover="showTip(event, '4', 16)" class="rt">Option</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 17)" onmouseover="showTip(event, '9', 17)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '4', 18)" onmouseover="showTip(event, '4', 18)" class="rt">Option</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 19)" onmouseover="showTip(event, '10', 19)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '11', 20)" onmouseover="showTip(event, '11', 20)" class="fn">x</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '12', 21)" onmouseover="showTip(event, '12', 21)" class="uc">Some</span> <span onmouseout="hideTip(event, '13', 22)" onmouseover="showTip(event, '13', 22)" class="fn">value</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '12', 23)" onmouseover="showTip(event, '12', 23)" class="uc">Some</span> <span class="pn">(</span><span onmouseout="hideTip(event, '2', 24)" onmouseover="showTip(event, '2', 24)" class="fn">f</span> <span onmouseout="hideTip(event, '13', 25)" onmouseover="showTip(event, '13', 25)" class="fn">value</span><span class="pn">)</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '14', 26)" onmouseover="showTip(event, '14', 26)" class="uc">None</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '14', 27)" onmouseover="showTip(event, '14', 27)" class="uc">None</span> </code></pre> <p>when looking at <code>map</code> as a function taking a single parameter its signature is</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="pn">(</span><span onmouseout="hideTip(event, '15', 28)" onmouseover="showTip(event, '15', 28)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '15', 29)" onmouseover="showTip(event, '15', 29)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span><span class="pn">)</span> </code></pre> <p><code>map</code> takes a <code>('a -&gt; 'b)</code> function and changes it in a <code>(Option&lt;'a&gt; -&gt; Option&lt;'b&gt;)</code> function.</p> <h3><a name="map2" class="anchor" href="#map2">map2</a></h3> <p><code>map</code> takes a single argument function <code>f</code> and makes it <code>Option</code> aware. But what about a function taking two arguments?</p> <p>We can define a <code>map2</code> function with the following signature:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">c</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="pn">(</span><span onmouseout="hideTip(event, '15', 30)" onmouseover="showTip(event, '15', 30)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '15', 31)" onmouseover="showTip(event, '15', 31)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '15', 32)" onmouseover="showTip(event, '15', 32)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">c</span><span class="pn">&gt;</span><span class="pn">)</span> </code></pre> <p>It takes the function and calls it with the values of the two other <code>Option</code> parameters if they both have a value. It returns <code>None</code> if any is <code>None</code>.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '16', 33)" onmouseover="showTip(event, '16', 33)" class="fn">map2</span> <span class="pn">(</span><span onmouseout="hideTip(event, '17', 34)" onmouseover="showTip(event, '17', 34)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 35)" onmouseover="showTip(event, '9', 35)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 36)" onmouseover="showTip(event, '10', 36)" class="id">b</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '18', 37)" onmouseover="showTip(event, '18', 37)" class="id">c</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '11', 38)" onmouseover="showTip(event, '11', 38)" class="fn">x</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 39)" onmouseover="showTip(event, '4', 39)" class="rt">Option</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 40)" onmouseover="showTip(event, '9', 40)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '19', 41)" onmouseover="showTip(event, '19', 41)" class="fn">y</span><span class="pn">:</span> <span onmouseout="hideTip(event, '4', 42)" onmouseover="showTip(event, '4', 42)" class="rt">Option</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 43)" onmouseover="showTip(event, '10', 43)" class="id">b</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '4', 44)" onmouseover="showTip(event, '4', 44)" class="rt">Option</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '18', 45)" onmouseover="showTip(event, '18', 45)" class="id">c</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '11', 46)" onmouseover="showTip(event, '11', 46)" class="fn">x</span><span class="pn">,</span><span onmouseout="hideTip(event, '19', 47)" onmouseover="showTip(event, '19', 47)" class="fn">y</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '12', 48)" onmouseover="showTip(event, '12', 48)" class="uc">Some</span> <span onmouseout="hideTip(event, '20', 49)" onmouseover="showTip(event, '20', 49)" class="fn">xvalue</span><span class="pn">,</span> <span onmouseout="hideTip(event, '12', 50)" onmouseover="showTip(event, '12', 50)" class="uc">Some</span> <span onmouseout="hideTip(event, '21', 51)" onmouseover="showTip(event, '21', 51)" class="fn">yvalue</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '12', 52)" onmouseover="showTip(event, '12', 52)" class="uc">Some</span> <span class="pn">(</span><span onmouseout="hideTip(event, '17', 53)" onmouseover="showTip(event, '17', 53)" class="fn">f</span> <span onmouseout="hideTip(event, '20', 54)" onmouseover="showTip(event, '20', 54)" class="fn">xvalue</span> <span onmouseout="hideTip(event, '21', 55)" onmouseover="showTip(event, '21', 55)" class="fn">yvalue</span><span class="pn">)</span> <span class="pn">|</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '14', 56)" onmouseover="showTip(event, '14', 56)" class="uc">None</span> </code></pre> <h3><a name="map3-map4" class="anchor" href="#map3-map4">map3, map4...</a></h3> <p>For a 3 arguments function, a 4 arguments function we'd then have to write extra <code>map</code> functions. That would be doable but tedious. And where should we stop?</p> <p>Let's take a simple two arguments function and see what happens when we use <code>map</code> on it:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '22', 57)" onmouseover="showTip(event, '22', 57)" class="fn">add</span> <span onmouseout="hideTip(event, '23', 58)" onmouseover="showTip(event, '23', 58)" class="fn">x</span> <span onmouseout="hideTip(event, '24', 59)" onmouseover="showTip(event, '24', 59)" class="fn">y</span> <span class="o">=</span> <span onmouseout="hideTip(event, '23', 60)" onmouseover="showTip(event, '23', 60)" class="fn">x</span> <span class="o">+</span> <span onmouseout="hideTip(event, '24', 61)" onmouseover="showTip(event, '24', 61)" class="fn">y</span> <span class="k">let</span> <span onmouseout="hideTip(event, '25', 62)" onmouseover="showTip(event, '25', 62)" class="fn">mappedAdd</span> <span class="o">=</span> <span onmouseout="hideTip(event, '8', 63)" onmouseover="showTip(event, '8', 63)" class="fn">map</span> <span onmouseout="hideTip(event, '22', 64)" onmouseover="showTip(event, '22', 64)" class="fn">add</span> </code></pre> <p>Notice first that it compiles because <code>add</code> can be seen as a one argument function returning another one argument function:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="k">let</span> <span class="id">add</span> <span class="id">x</span> <span class="o">=</span> <span class="k">fun</span> <span class="id">y</span> <span class="k">-&gt;</span> <span class="id">x</span> <span class="o">+</span> <span class="id">y</span> </code></pre> <p>So its signature can be read as <code>(int -&gt; (int -&gt; int))</code></p> <p>Using <code>map</code>, it will become:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span onmouseout="hideTip(event, '15', 65)" onmouseover="showTip(event, '15', 65)" class="id">Option</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '26', 66)" onmouseover="showTip(event, '26', 66)" class="id">int</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '15', 67)" onmouseover="showTip(event, '15', 67)" class="id">Option</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '26', 68)" onmouseover="showTip(event, '26', 68)" class="id">int</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '26', 69)" onmouseover="showTip(event, '26', 69)" class="id">int</span><span class="pn">&gt;</span> </code></pre> <p>If you call it with the value <code>Some 3</code>, the result will be <code>Some</code> function that takes an <code>int</code> and adds 3 to it. Called with <code>None</code>, you get no function.</p> <p>Lets take the most basic function application:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '1', 70)" onmouseover="showTip(event, '1', 70)" class="fn">basicApply</span> <span onmouseout="hideTip(event, '2', 71)" onmouseover="showTip(event, '2', 71)" class="fn">f</span> <span onmouseout="hideTip(event, '3', 72)" onmouseover="showTip(event, '3', 72)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '2', 73)" onmouseover="showTip(event, '2', 73)" class="fn">f</span> <span onmouseout="hideTip(event, '3', 74)" onmouseover="showTip(event, '3', 74)" class="fn">x</span> </code></pre> <p><code>basicApply</code> is a function that takes a function f, a value v, and passes the value v to the function f (this is the F# <code>&lt;|</code> operator).</p> <p>we can make it work with <code>Option</code> using <code>map2</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '27', 75)" onmouseover="showTip(event, '27', 75)" class="fn">apply</span> <span onmouseout="hideTip(event, '28', 76)" onmouseover="showTip(event, '28', 76)" class="fn">f</span> <span onmouseout="hideTip(event, '11', 77)" onmouseover="showTip(event, '11', 77)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '16', 78)" onmouseover="showTip(event, '16', 78)" class="fn">map2</span> <span onmouseout="hideTip(event, '1', 79)" onmouseover="showTip(event, '1', 79)" class="fn">basicApply</span> <span onmouseout="hideTip(event, '28', 80)" onmouseover="showTip(event, '28', 80)" class="fn">f</span> <span onmouseout="hideTip(event, '11', 81)" onmouseover="showTip(event, '11', 81)" class="fn">x</span> </code></pre> <p><code>basicApply</code> signature is</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span> </code></pre> <p>and we can look at it as a 2 arguments function:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="pn">(</span><span class="pn">(</span><span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">a</span><span class="pn">)</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span> </code></pre> <p>And <code>map2</code> will change it to:</p> <pre class="fssnip highlighted"><code lang="fsharp"><span class="pn">(</span><span onmouseout="hideTip(event, '15', 82)" onmouseover="showTip(event, '15', 82)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span> <span class="k">-&gt;</span> <span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '15', 83)" onmouseover="showTip(event, '15', 83)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '15', 84)" onmouseover="showTip(event, '15', 84)" class="id">Option</span><span class="pn">&lt;</span><span class="id">&#39;</span><span class="id">b</span><span class="pn">&gt;</span> </code></pre> <p>This is a function that takes an optional function as first argument and an optional value as a second argument. If both have a value, the value is passed to the function. If any is <code>None</code> the result is <code>None</code>.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '29', 85)" onmouseover="showTip(event, '29', 85)" class="id">partialAdd</span> <span class="o">=</span> <span onmouseout="hideTip(event, '8', 86)" onmouseover="showTip(event, '8', 86)" class="fn">map</span> <span onmouseout="hideTip(event, '22', 87)" onmouseover="showTip(event, '22', 87)" class="fn">add</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 88)" onmouseover="showTip(event, '12', 88)" class="uc">Some</span> <span class="n">3</span><span class="pn">)</span> <span class="c">// Some(fun y -&gt; 3 + Y)</span> <span onmouseout="hideTip(event, '27', 89)" onmouseover="showTip(event, '27', 89)" class="fn">apply</span> <span onmouseout="hideTip(event, '29', 90)" onmouseover="showTip(event, '29', 90)" class="id">partialAdd</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 91)" onmouseover="showTip(event, '12', 91)" class="uc">Some</span> <span class="n">5</span><span class="pn">)</span> <span class="c">// Some(3 + 5) =&gt; Some 8</span> </code></pre> <table class="pre"><tr><td><pre><code>Some 8</code></pre></td></tr></table> <p>The nice thing is that it works for functions with more than 2 arguments since any function can be considered as a function of 1 argument.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '30', 92)" onmouseover="showTip(event, '30', 92)" class="rt">User</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 93)" onmouseover="showTip(event, '31', 93)" class="rt">string</span> <span class="prop">LastName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 94)" onmouseover="showTip(event, '31', 94)" class="rt">string</span> <span class="prop">Age</span><span class="pn">:</span> <span onmouseout="hideTip(event, '26', 95)" onmouseover="showTip(event, '26', 95)" class="vt">int</span> <span class="prop">FavoriteLanguage</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 96)" onmouseover="showTip(event, '31', 96)" class="rt">string</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '32', 97)" onmouseover="showTip(event, '32', 97)" class="fn">user</span> <span onmouseout="hideTip(event, '33', 98)" onmouseover="showTip(event, '33', 98)" class="fn">firstname</span> <span onmouseout="hideTip(event, '34', 99)" onmouseover="showTip(event, '34', 99)" class="fn">lastname</span> <span onmouseout="hideTip(event, '35', 100)" onmouseover="showTip(event, '35', 100)" class="fn">age</span> <span onmouseout="hideTip(event, '36', 101)" onmouseover="showTip(event, '36', 101)" class="fn">favoriteLang</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 102)" onmouseover="showTip(event, '33', 102)" class="fn">firstname</span> <span class="prop">LastName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '34', 103)" onmouseover="showTip(event, '34', 103)" class="fn">lastname</span> <span class="prop">Age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '35', 104)" onmouseover="showTip(event, '35', 104)" class="fn">age</span> <span class="prop">FavoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 105)" onmouseover="showTip(event, '36', 105)" class="fn">favoriteLang</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '37', 106)" onmouseover="showTip(event, '37', 106)" class="id">user&#39;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '8', 107)" onmouseover="showTip(event, '8', 107)" class="fn">map</span> <span onmouseout="hideTip(event, '32', 108)" onmouseover="showTip(event, '32', 108)" class="fn">user</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 109)" onmouseover="showTip(event, '12', 109)" class="uc">Some</span> <span class="s">&quot;John&quot;</span><span class="pn">)</span> <span class="c">// Option&lt;string -&gt; int -&gt; string -&gt; User&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '38', 110)" onmouseover="showTip(event, '38', 110)" class="id">user&#39;&#39;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '27', 111)" onmouseover="showTip(event, '27', 111)" class="fn">apply</span> <span onmouseout="hideTip(event, '37', 112)" onmouseover="showTip(event, '37', 112)" class="id">user&#39;</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 113)" onmouseover="showTip(event, '12', 113)" class="uc">Some</span> <span class="s">&quot;Doe&quot;</span><span class="pn">)</span> <span class="c">// Option&lt;int -&gt; string -&gt; User&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '39', 114)" onmouseover="showTip(event, '39', 114)" class="id">user&#39;&#39;&#39;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '27', 115)" onmouseover="showTip(event, '27', 115)" class="fn">apply</span> <span onmouseout="hideTip(event, '38', 116)" onmouseover="showTip(event, '38', 116)" class="id">user&#39;&#39;</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 117)" onmouseover="showTip(event, '12', 117)" class="uc">Some</span> <span class="n">42</span><span class="pn">)</span> <span class="c">// Option&lt;string -&gt; User&gt;</span> <span onmouseout="hideTip(event, '27', 118)" onmouseover="showTip(event, '27', 118)" class="fn">apply</span> <span onmouseout="hideTip(event, '39', 119)" onmouseover="showTip(event, '39', 119)" class="id">user&#39;&#39;&#39;</span> <span class="pn">(</span><span onmouseout="hideTip(event, '12', 120)" onmouseover="showTip(event, '12', 120)" class="uc">Some</span> <span class="s">&quot;F#&quot;</span><span class="pn">)</span> <span class="c">// Option&lt;User&gt;</span> </code></pre> <table class="pre"><tr><td><pre><code>Some { FirstName = "John" LastName = "Doe" Age = 42 FavoriteLanguage = "F#" }</code></pre></td></tr></table> <p>Luckily we can simplify the writing by defining two infix operators for <code>map</code> and <code>apply</code>.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;!&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '8', 121)" onmouseover="showTip(event, '8', 121)" class="fn">map</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;*&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '27', 122)" onmouseover="showTip(event, '27', 122)" class="fn">apply</span> </code></pre> <p>Now we can write</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span onmouseout="hideTip(event, '32', 123)" onmouseover="showTip(event, '32', 123)" class="fn">user</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '12', 124)" onmouseover="showTip(event, '12', 124)" class="uc">Some</span> <span class="s">&quot;John&quot;</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '12', 125)" onmouseover="showTip(event, '12', 125)" class="uc">Some</span> <span class="s">&quot;Doe&quot;</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '12', 126)" onmouseover="showTip(event, '12', 126)" class="uc">Some</span> <span class="n">42</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '12', 127)" onmouseover="showTip(event, '12', 127)" class="uc">Some</span> <span class="s">&quot;F#&quot;</span> </code></pre> <p>this is very useful with validation, and you can easily do the same thing for <code>Result&lt;'a,string&gt;</code> type, a type that has either a value of type <code>'a</code>, or an error message. <code>map</code> is already defined and we have to write a <code>map2</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '40', 128)" onmouseover="showTip(event, '40', 128)" class="fn">map2</span> <span class="pn">(</span><span onmouseout="hideTip(event, '17', 129)" onmouseover="showTip(event, '17', 129)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 130)" onmouseover="showTip(event, '9', 130)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 131)" onmouseover="showTip(event, '10', 131)" class="id">b</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '18', 132)" onmouseover="showTip(event, '18', 132)" class="id">c</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '41', 133)" onmouseover="showTip(event, '41', 133)" class="fn">xresult</span><span class="pn">:</span> <span onmouseout="hideTip(event, '42', 134)" onmouseover="showTip(event, '42', 134)" class="vt">Result</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 135)" onmouseover="showTip(event, '9', 135)" class="id">a</span><span class="pn">,</span> <span onmouseout="hideTip(event, '31', 136)" onmouseover="showTip(event, '31', 136)" class="rt">string</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '43', 137)" onmouseover="showTip(event, '43', 137)" class="fn">yresult</span><span class="pn">:</span> <span onmouseout="hideTip(event, '42', 138)" onmouseover="showTip(event, '42', 138)" class="vt">Result</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 139)" onmouseover="showTip(event, '10', 139)" class="id">b</span><span class="pn">,</span> <span onmouseout="hideTip(event, '31', 140)" onmouseover="showTip(event, '31', 140)" class="rt">string</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '42', 141)" onmouseover="showTip(event, '42', 141)" class="vt">Result</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '18', 142)" onmouseover="showTip(event, '18', 142)" class="id">c</span><span class="pn">,</span> <span onmouseout="hideTip(event, '31', 143)" onmouseover="showTip(event, '31', 143)" class="rt">string</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '41', 144)" onmouseover="showTip(event, '41', 144)" class="fn">xresult</span><span class="pn">,</span> <span onmouseout="hideTip(event, '43', 145)" onmouseover="showTip(event, '43', 145)" class="fn">yresult</span> <span class="k">with</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '44', 146)" onmouseover="showTip(event, '44', 146)" class="uc">Ok</span> <span onmouseout="hideTip(event, '3', 147)" onmouseover="showTip(event, '3', 147)" class="fn">x</span><span class="pn">,</span> <span onmouseout="hideTip(event, '44', 148)" onmouseover="showTip(event, '44', 148)" class="uc">Ok</span> <span onmouseout="hideTip(event, '45', 149)" onmouseover="showTip(event, '45', 149)" class="fn">y</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '44', 150)" onmouseover="showTip(event, '44', 150)" class="uc">Ok</span> <span class="pn">(</span><span onmouseout="hideTip(event, '17', 151)" onmouseover="showTip(event, '17', 151)" class="fn">f</span> <span onmouseout="hideTip(event, '3', 152)" onmouseover="showTip(event, '3', 152)" class="fn">x</span> <span onmouseout="hideTip(event, '45', 153)" onmouseover="showTip(event, '45', 153)" class="fn">y</span><span class="pn">)</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '46', 154)" onmouseover="showTip(event, '46', 154)" class="uc">Error</span> <span onmouseout="hideTip(event, '47', 155)" onmouseover="showTip(event, '47', 155)" class="fn">fe</span><span class="pn">,</span> <span onmouseout="hideTip(event, '44', 156)" onmouseover="showTip(event, '44', 156)" class="uc">Ok</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '46', 157)" onmouseover="showTip(event, '46', 157)" class="uc">Error</span> <span onmouseout="hideTip(event, '47', 158)" onmouseover="showTip(event, '47', 158)" class="fn">fe</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '44', 159)" onmouseover="showTip(event, '44', 159)" class="uc">Ok</span> <span class="id">_</span><span class="pn">,</span> <span onmouseout="hideTip(event, '46', 160)" onmouseover="showTip(event, '46', 160)" class="uc">Error</span> <span onmouseout="hideTip(event, '48', 161)" onmouseover="showTip(event, '48', 161)" class="fn">xe</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '46', 162)" onmouseover="showTip(event, '46', 162)" class="uc">Error</span> <span onmouseout="hideTip(event, '48', 163)" onmouseover="showTip(event, '48', 163)" class="fn">xe</span> <span class="pn">|</span> <span onmouseout="hideTip(event, '46', 164)" onmouseover="showTip(event, '46', 164)" class="uc">Error</span> <span onmouseout="hideTip(event, '47', 165)" onmouseover="showTip(event, '47', 165)" class="fn">fe</span><span class="pn">,</span> <span onmouseout="hideTip(event, '46', 166)" onmouseover="showTip(event, '46', 166)" class="uc">Error</span> <span onmouseout="hideTip(event, '48', 167)" onmouseover="showTip(event, '48', 167)" class="fn">xe</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '46', 168)" onmouseover="showTip(event, '46', 168)" class="uc">Error</span> <span class="pn">(</span><span onmouseout="hideTip(event, '47', 169)" onmouseover="showTip(event, '47', 169)" class="fn">fe</span> <span class="o">+</span> <span class="s">&quot;\n&quot;</span> <span class="o">+</span> <span onmouseout="hideTip(event, '48', 170)" onmouseover="showTip(event, '48', 170)" class="fn">xe</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '49', 171)" onmouseover="showTip(event, '49', 171)" class="fn">apply</span> <span onmouseout="hideTip(event, '50', 172)" onmouseover="showTip(event, '50', 172)" class="fn">f</span> <span onmouseout="hideTip(event, '51', 173)" onmouseover="showTip(event, '51', 173)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '40', 174)" onmouseover="showTip(event, '40', 174)" class="fn">map2</span> <span onmouseout="hideTip(event, '1', 175)" onmouseover="showTip(event, '1', 175)" class="fn">basicApply</span> <span onmouseout="hideTip(event, '50', 176)" onmouseover="showTip(event, '50', 176)" class="fn">f</span> <span onmouseout="hideTip(event, '51', 177)" onmouseover="showTip(event, '51', 177)" class="fn">x</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;!&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '42', 178)" onmouseover="showTip(event, '42', 178)" class="m">Result</span><span class="pn">.</span><span onmouseout="hideTip(event, '52', 179)" onmouseover="showTip(event, '52', 179)" class="id">map</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;*&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '49', 180)" onmouseover="showTip(event, '49', 180)" class="fn">apply</span> <span class="k">open</span> <span onmouseout="hideTip(event, '53', 181)" onmouseover="showTip(event, '53', 181)" class="id">System</span> <span class="k">let</span> <span onmouseout="hideTip(event, '54', 182)" onmouseover="showTip(event, '54', 182)" class="fn">notEmpty</span> <span onmouseout="hideTip(event, '55', 183)" onmouseover="showTip(event, '55', 183)" class="fn">prop</span> <span onmouseout="hideTip(event, '56', 184)" onmouseover="showTip(event, '56', 184)" class="fn">value</span> <span class="o">=</span> <span class="k">if</span> <span onmouseout="hideTip(event, '57', 185)" onmouseover="showTip(event, '57', 185)" class="m">String</span><span class="pn">.</span><span onmouseout="hideTip(event, '58', 186)" onmouseover="showTip(event, '58', 186)" class="id">IsNullOrEmpty</span> <span onmouseout="hideTip(event, '56', 187)" onmouseover="showTip(event, '56', 187)" class="fn">value</span> <span class="k">then</span> <span onmouseout="hideTip(event, '46', 188)" onmouseover="showTip(event, '46', 188)" class="uc">Error</span> <span class="pn">(</span><span onmouseout="hideTip(event, '59', 189)" onmouseover="showTip(event, '59', 189)" class="fn">sprintf</span> <span class="s">&quot;</span><span class="pf">%s</span><span class="s"> should not be empty&quot;</span> <span onmouseout="hideTip(event, '55', 190)" onmouseover="showTip(event, '55', 190)" class="fn">prop</span><span class="pn">)</span> <span class="k">else</span> <span onmouseout="hideTip(event, '44', 191)" onmouseover="showTip(event, '44', 191)" class="uc">Ok</span> <span onmouseout="hideTip(event, '56', 192)" onmouseover="showTip(event, '56', 192)" class="fn">value</span> <span class="k">let</span> <span onmouseout="hideTip(event, '60', 193)" onmouseover="showTip(event, '60', 193)" class="fn">tryParse</span> <span onmouseout="hideTip(event, '55', 194)" onmouseover="showTip(event, '55', 194)" class="fn">prop</span> <span onmouseout="hideTip(event, '61', 195)" onmouseover="showTip(event, '61', 195)" class="fn">input</span> <span class="o">=</span> <span class="k">match</span> <span onmouseout="hideTip(event, '62', 196)" onmouseover="showTip(event, '62', 196)" class="vt">Int32</span><span class="pn">.</span><span onmouseout="hideTip(event, '63', 197)" onmouseover="showTip(event, '63', 197)" class="id">TryParse</span><span class="pn">(</span><span onmouseout="hideTip(event, '61', 198)" onmouseover="showTip(event, '61', 198)" class="fn">input</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 199)" onmouseover="showTip(event, '64', 199)" class="rt">string</span><span class="pn">)</span> <span class="k">with</span> <span class="pn">|</span> <span class="k">true</span><span class="pn">,</span> <span onmouseout="hideTip(event, '65', 200)" onmouseover="showTip(event, '65', 200)" class="fn">value</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '44', 201)" onmouseover="showTip(event, '44', 201)" class="uc">Ok</span> <span onmouseout="hideTip(event, '65', 202)" onmouseover="showTip(event, '65', 202)" class="fn">value</span> <span class="pn">|</span> <span class="k">false</span><span class="pn">,</span> <span class="id">_</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '46', 203)" onmouseover="showTip(event, '46', 203)" class="uc">Error</span> <span class="pn">(</span><span onmouseout="hideTip(event, '59', 204)" onmouseover="showTip(event, '59', 204)" class="fn">sprintf</span> <span class="s">&quot;</span><span class="pf">%s</span><span class="s"> should be an number&quot;</span> <span onmouseout="hideTip(event, '55', 205)" onmouseover="showTip(event, '55', 205)" class="fn">prop</span><span class="pn">)</span> <span class="c">// define a user as previously</span> <span class="k">type</span> <span onmouseout="hideTip(event, '30', 206)" onmouseover="showTip(event, '30', 206)" class="rt">User</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 207)" onmouseover="showTip(event, '64', 207)" class="rt">string</span> <span class="prop">LastName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 208)" onmouseover="showTip(event, '64', 208)" class="rt">string</span> <span class="prop">Age</span><span class="pn">:</span> <span onmouseout="hideTip(event, '26', 209)" onmouseover="showTip(event, '26', 209)" class="vt">int</span> <span class="prop">FavoriteLanguage</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 210)" onmouseover="showTip(event, '64', 210)" class="rt">string</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '32', 211)" onmouseover="showTip(event, '32', 211)" class="fn">user</span> <span onmouseout="hideTip(event, '33', 212)" onmouseover="showTip(event, '33', 212)" class="fn">firstname</span> <span onmouseout="hideTip(event, '34', 213)" onmouseover="showTip(event, '34', 213)" class="fn">lastname</span> <span onmouseout="hideTip(event, '35', 214)" onmouseover="showTip(event, '35', 214)" class="fn">age</span> <span onmouseout="hideTip(event, '36', 215)" onmouseover="showTip(event, '36', 215)" class="fn">favoriteLang</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 216)" onmouseover="showTip(event, '33', 216)" class="fn">firstname</span> <span class="prop">LastName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '34', 217)" onmouseover="showTip(event, '34', 217)" class="fn">lastname</span> <span class="prop">Age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '35', 218)" onmouseover="showTip(event, '35', 218)" class="fn">age</span> <span class="prop">FavoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 219)" onmouseover="showTip(event, '36', 219)" class="fn">favoriteLang</span> <span class="pn">}</span> <span onmouseout="hideTip(event, '32', 220)" onmouseover="showTip(event, '32', 220)" class="fn">user</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '54', 221)" onmouseover="showTip(event, '54', 221)" class="fn">notEmpty</span> <span class="s">&quot;firstname&quot;</span> <span class="s">&quot;John&quot;</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '54', 222)" onmouseover="showTip(event, '54', 222)" class="fn">notEmpty</span> <span class="s">&quot;lastname&quot;</span> <span class="s">&quot;Doe&quot;</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '60', 223)" onmouseover="showTip(event, '60', 223)" class="fn">tryParse</span> <span class="s">&quot;age&quot;</span> <span class="s">&quot;42&quot;</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '54', 224)" onmouseover="showTip(event, '54', 224)" class="fn">notEmpty</span> <span class="s">&quot;favorite language&quot;</span> <span class="s">&quot;F#&quot;</span> </code></pre> <p>Now try to play with the input values and look at the result. Instead of getting <code>Ok</code> with a typed user, you'll get an error with a message describing why the user could not be constructed. Neat!</p> <h2><a name="Series" class="anchor" href="#Series">Series</a></h2> <p>Applicatives can be defined on anything on which we can write a <code>map2</code> function. Any construct that is <strong>zippable</strong>.</p> <p>A good example of a zippable, non trivial structure is a time series. Let's define one:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '66', 226)" onmouseover="showTip(event, '66', 226)" class="rt">Series</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 227)" onmouseover="showTip(event, '9', 227)" class="id">a</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '67', 228)" onmouseover="showTip(event, '67', 228)" class="uc">Series</span> <span class="k">of</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 229)" onmouseover="showTip(event, '9', 229)" class="id">a</span> <span class="pn">*</span> <span class="pn">(</span><span onmouseout="hideTip(event, '68', 230)" onmouseover="showTip(event, '68', 230)" class="vt">DateTime</span> <span class="pn">*</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 231)" onmouseover="showTip(event, '9', 231)" class="id">a</span><span class="pn">)</span> <span onmouseout="hideTip(event, '69', 232)" onmouseover="showTip(event, '69', 232)" class="rt">list</span> </code></pre> <p>It has an initial value of type <code>'a</code> and a list of changes consisting of the date of change and the new value.</p> <p>For instance we can easily build constant series like this:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '70', 233)" onmouseover="showTip(event, '70', 233)" class="fn">always</span> <span onmouseout="hideTip(event, '3', 234)" onmouseover="showTip(event, '3', 234)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '66', 235)" onmouseover="showTip(event, '66', 235)" class="uc">Series</span><span class="pn">(</span><span onmouseout="hideTip(event, '3', 236)" onmouseover="showTip(event, '3', 236)" class="fn">x</span><span class="pn">,</span> <span class="pn">[</span><span class="pn">]</span><span class="pn">)</span> </code></pre> <p>it defines a <code>Series</code> with initial value x that never changes.</p> <p>We can also define a <code>map</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '71', 237)" onmouseover="showTip(event, '71', 237)" class="fn">map</span> <span onmouseout="hideTip(event, '2', 238)" onmouseover="showTip(event, '2', 238)" class="fn">f</span> <span class="pn">(</span><span onmouseout="hideTip(event, '66', 239)" onmouseover="showTip(event, '66', 239)" class="id">Series</span><span class="pn">(</span><span onmouseout="hideTip(event, '72', 240)" onmouseover="showTip(event, '72', 240)" class="fn">initial</span><span class="pn">,</span> <span onmouseout="hideTip(event, '73', 241)" onmouseover="showTip(event, '73', 241)" class="fn">changes</span><span class="pn">)</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '66', 242)" onmouseover="showTip(event, '66', 242)" class="uc">Series</span><span class="pn">(</span> <span onmouseout="hideTip(event, '2', 243)" onmouseover="showTip(event, '2', 243)" class="fn">f</span> <span class="fn">initial</span><span class="pn">,</span> <span onmouseout="hideTip(event, '74', 244)" onmouseover="showTip(event, '74', 244)" class="m">List</span><span class="pn">.</span><span onmouseout="hideTip(event, '75', 245)" onmouseover="showTip(event, '75', 245)" class="id">map</span> <span class="pn">(</span><span class="k">fun</span> <span class="pn">(</span><span onmouseout="hideTip(event, '76', 246)" onmouseover="showTip(event, '76', 246)" class="fn">d</span><span class="pn">,</span><span onmouseout="hideTip(event, '77', 247)" onmouseover="showTip(event, '77', 247)" class="fn">v</span><span class="pn">)</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '76', 248)" onmouseover="showTip(event, '76', 248)" class="fn">d</span><span class="pn">,</span> <span onmouseout="hideTip(event, '2', 249)" onmouseover="showTip(event, '2', 249)" class="fn">f</span> <span onmouseout="hideTip(event, '77', 250)" onmouseover="showTip(event, '77', 250)" class="fn">v</span><span class="pn">)</span> <span onmouseout="hideTip(event, '73', 251)" onmouseover="showTip(event, '73', 251)" class="fn">changes</span><span class="pn">)</span> </code></pre> <p>It applies the function f to the initial value and every change values.</p> <p><code>map2</code> is a bit more convoluted. The two series start with an initial value that can be fed to the given function. After that, one of the series changes, and we call f with the initial value of the one that didn't change and the new value of the other one.. each time a value changes, we use this value and the last known value of the other one. We use a recursive function for this.</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '78', 252)" onmouseover="showTip(event, '78', 252)" class="fn">map2</span> <span onmouseout="hideTip(event, '17', 253)" onmouseover="showTip(event, '17', 253)" class="fn">f</span> <span class="pn">(</span><span onmouseout="hideTip(event, '66', 254)" onmouseover="showTip(event, '66', 254)" class="id">Series</span><span class="pn">(</span><span onmouseout="hideTip(event, '79', 255)" onmouseover="showTip(event, '79', 255)" class="fn">ix</span><span class="pn">,</span> <span onmouseout="hideTip(event, '80', 256)" onmouseover="showTip(event, '80', 256)" class="fn">cx</span><span class="pn">)</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '66', 257)" onmouseover="showTip(event, '66', 257)" class="id">Series</span><span class="pn">(</span><span onmouseout="hideTip(event, '81', 258)" onmouseover="showTip(event, '81', 258)" class="fn">iy</span><span class="pn">,</span> <span onmouseout="hideTip(event, '82', 259)" onmouseover="showTip(event, '82', 259)" class="fn">cy</span><span class="pn">)</span><span class="pn">)</span> <span class="o">=</span> <span class="k">let</span> <span class="k">rec</span> <span onmouseout="hideTip(event, '83', 260)" onmouseover="showTip(event, '83', 260)" class="fn">zip</span> <span onmouseout="hideTip(event, '84', 261)" onmouseover="showTip(event, '84', 261)" class="fn">lastx</span> <span onmouseout="hideTip(event, '85', 262)" onmouseover="showTip(event, '85', 262)" class="fn">lasty</span> <span onmouseout="hideTip(event, '86', 263)" onmouseover="showTip(event, '86', 263)" class="fn">changesx</span> <span onmouseout="hideTip(event, '87', 264)" onmouseover="showTip(event, '87', 264)" class="fn">changesy</span> <span class="o">=</span> <span class="pn">[</span> <span class="k">match</span> <span onmouseout="hideTip(event, '86', 265)" onmouseover="showTip(event, '86', 265)" class="fn">changesx</span><span class="pn">,</span> <span onmouseout="hideTip(event, '87', 266)" onmouseover="showTip(event, '87', 266)" class="fn">changesy</span> <span class="k">with</span> <span class="pn">|</span> <span class="pn">[</span><span class="pn">]</span><span class="pn">,</span><span class="pn">[</span><span class="pn">]</span> <span class="k">-&gt;</span> <span class="pn">(</span><span class="pn">)</span> <span class="c">// we&#39;re done</span> <span class="pn">|</span> <span class="pn">[</span><span class="pn">]</span><span class="pn">,</span> <span class="id">_</span> <span class="k">-&gt;</span> <span class="c">// x won&#39;t change anymore</span> <span class="k">for</span> <span onmouseout="hideTip(event, '88', 267)" onmouseover="showTip(event, '88', 267)" class="fn">d</span><span class="pn">,</span><span onmouseout="hideTip(event, '45', 268)" onmouseover="showTip(event, '45', 268)" class="fn">y</span> <span class="k">in</span> <span onmouseout="hideTip(event, '87', 269)" onmouseover="showTip(event, '87', 269)" class="fn">changesy</span> <span class="k">do</span> <span onmouseout="hideTip(event, '88', 270)" onmouseover="showTip(event, '88', 270)" class="fn">d</span><span class="pn">,</span> <span onmouseout="hideTip(event, '17', 271)" onmouseover="showTip(event, '17', 271)" class="fn">f</span> <span onmouseout="hideTip(event, '84', 272)" onmouseover="showTip(event, '84', 272)" class="fn">lastx</span> <span onmouseout="hideTip(event, '45', 273)" onmouseover="showTip(event, '45', 273)" class="fn">y</span> <span class="pn">|</span> <span class="id">_</span><span class="pn">,</span> <span class="pn">[</span><span class="pn">]</span> <span class="k">-&gt;</span> <span class="c">// y won&#39;t change anymore</span> <span class="k">for</span> <span onmouseout="hideTip(event, '88', 274)" onmouseover="showTip(event, '88', 274)" class="fn">d</span><span class="pn">,</span><span onmouseout="hideTip(event, '3', 275)" onmouseover="showTip(event, '3', 275)" class="fn">x</span> <span class="k">in</span> <span onmouseout="hideTip(event, '86', 276)" onmouseover="showTip(event, '86', 276)" class="fn">changesx</span> <span class="k">do</span> <span onmouseout="hideTip(event, '88', 277)" onmouseover="showTip(event, '88', 277)" class="fn">d</span><span class="pn">,</span> <span onmouseout="hideTip(event, '17', 278)" onmouseover="showTip(event, '17', 278)" class="fn">f</span> <span onmouseout="hideTip(event, '3', 279)" onmouseover="showTip(event, '3', 279)" class="fn">x</span> <span onmouseout="hideTip(event, '85', 280)" onmouseover="showTip(event, '85', 280)" class="fn">lasty</span> <span class="pn">|</span> <span class="pn">(</span><span onmouseout="hideTip(event, '89', 281)" onmouseover="showTip(event, '89', 281)" class="fn">dx</span><span class="pn">,</span><span onmouseout="hideTip(event, '3', 282)" onmouseover="showTip(event, '3', 282)" class="fn">x</span><span class="pn">)</span> <span class="uc">::</span> <span onmouseout="hideTip(event, '90', 283)" onmouseover="showTip(event, '90', 283)" class="fn">tailx</span> <span class="pn">,</span> <span class="pn">(</span><span onmouseout="hideTip(event, '91', 284)" onmouseover="showTip(event, '91', 284)" class="fn">dy</span><span class="pn">,</span><span onmouseout="hideTip(event, '45', 285)" onmouseover="showTip(event, '45', 285)" class="fn">y</span><span class="pn">)</span> <span class="uc">::</span> <span onmouseout="hideTip(event, '92', 286)" onmouseover="showTip(event, '92', 286)" class="fn">taily</span> <span class="k">-&gt;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '89', 287)" onmouseover="showTip(event, '89', 287)" class="fn">dx</span> <span class="o">&lt;</span> <span onmouseout="hideTip(event, '91', 288)" onmouseover="showTip(event, '91', 288)" class="fn">dy</span> <span class="k">then</span> <span class="c">// x changes before y</span> <span onmouseout="hideTip(event, '89', 289)" onmouseover="showTip(event, '89', 289)" class="fn">dx</span><span class="pn">,</span> <span onmouseout="hideTip(event, '17', 290)" onmouseover="showTip(event, '17', 290)" class="fn">f</span> <span onmouseout="hideTip(event, '3', 291)" onmouseover="showTip(event, '3', 291)" class="fn">x</span> <span onmouseout="hideTip(event, '85', 292)" onmouseover="showTip(event, '85', 292)" class="fn">lasty</span> <span class="k">yield!</span> <span onmouseout="hideTip(event, '83', 293)" onmouseover="showTip(event, '83', 293)" class="fn">zip</span> <span onmouseout="hideTip(event, '3', 294)" onmouseover="showTip(event, '3', 294)" class="fn">x</span> <span onmouseout="hideTip(event, '85', 295)" onmouseover="showTip(event, '85', 295)" class="fn">lasty</span> <span onmouseout="hideTip(event, '90', 296)" onmouseover="showTip(event, '90', 296)" class="fn">tailx</span> <span onmouseout="hideTip(event, '87', 297)" onmouseover="showTip(event, '87', 297)" class="fn">changesy</span> <span class="k">elif</span> <span onmouseout="hideTip(event, '91', 298)" onmouseover="showTip(event, '91', 298)" class="fn">dy</span> <span class="o">&lt;</span> <span onmouseout="hideTip(event, '89', 299)" onmouseover="showTip(event, '89', 299)" class="fn">dx</span> <span class="k">then</span> <span class="c">// y changes before x</span> <span onmouseout="hideTip(event, '91', 300)" onmouseover="showTip(event, '91', 300)" class="fn">dy</span><span class="pn">,</span> <span onmouseout="hideTip(event, '17', 301)" onmouseover="showTip(event, '17', 301)" class="fn">f</span> <span onmouseout="hideTip(event, '84', 302)" onmouseover="showTip(event, '84', 302)" class="fn">lastx</span> <span onmouseout="hideTip(event, '45', 303)" onmouseover="showTip(event, '45', 303)" class="fn">y</span> <span class="k">yield!</span> <span onmouseout="hideTip(event, '83', 304)" onmouseover="showTip(event, '83', 304)" class="fn">zip</span> <span onmouseout="hideTip(event, '84', 305)" onmouseover="showTip(event, '84', 305)" class="fn">lastx</span> <span onmouseout="hideTip(event, '45', 306)" onmouseover="showTip(event, '45', 306)" class="fn">y</span> <span onmouseout="hideTip(event, '86', 307)" onmouseover="showTip(event, '86', 307)" class="fn">changesx</span> <span onmouseout="hideTip(event, '92', 308)" onmouseover="showTip(event, '92', 308)" class="fn">taily</span> <span class="k">else</span> <span class="c">// x and y change at the same time</span> <span class="c">// dx is equal to dy</span> <span onmouseout="hideTip(event, '89', 309)" onmouseover="showTip(event, '89', 309)" class="fn">dx</span><span class="pn">,</span> <span onmouseout="hideTip(event, '17', 310)" onmouseover="showTip(event, '17', 310)" class="fn">f</span> <span onmouseout="hideTip(event, '3', 311)" onmouseover="showTip(event, '3', 311)" class="fn">x</span> <span onmouseout="hideTip(event, '45', 312)" onmouseover="showTip(event, '45', 312)" class="fn">y</span> <span class="k">yield!</span> <span onmouseout="hideTip(event, '83', 313)" onmouseover="showTip(event, '83', 313)" class="fn">zip</span> <span onmouseout="hideTip(event, '3', 314)" onmouseover="showTip(event, '3', 314)" class="fn">x</span> <span onmouseout="hideTip(event, '45', 315)" onmouseover="showTip(event, '45', 315)" class="fn">y</span> <span onmouseout="hideTip(event, '90', 316)" onmouseover="showTip(event, '90', 316)" class="fn">tailx</span> <span onmouseout="hideTip(event, '92', 317)" onmouseover="showTip(event, '92', 317)" class="fn">taily</span> <span class="pn">]</span> <span onmouseout="hideTip(event, '66', 318)" onmouseover="showTip(event, '66', 318)" class="uc">Series</span><span class="pn">(</span><span onmouseout="hideTip(event, '17', 319)" onmouseover="showTip(event, '17', 319)" class="fn">f</span> <span onmouseout="hideTip(event, '79', 320)" onmouseover="showTip(event, '79', 320)" class="fn">ix</span> <span onmouseout="hideTip(event, '81', 321)" onmouseover="showTip(event, '81', 321)" class="fn">iy</span><span class="pn">,</span> <span onmouseout="hideTip(event, '83', 322)" onmouseover="showTip(event, '83', 322)" class="fn">zip</span> <span onmouseout="hideTip(event, '79', 323)" onmouseover="showTip(event, '79', 323)" class="fn">ix</span> <span onmouseout="hideTip(event, '81', 324)" onmouseover="showTip(event, '81', 324)" class="fn">iy</span> <span onmouseout="hideTip(event, '80', 325)" onmouseover="showTip(event, '80', 325)" class="fn">cx</span> <span onmouseout="hideTip(event, '82', 326)" onmouseover="showTip(event, '82', 326)" class="fn">cy</span><span class="pn">)</span> </code></pre> <p>using <code>map2</code> we can add two series:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '22', 327)" onmouseover="showTip(event, '22', 327)" class="fn">add</span> <span onmouseout="hideTip(event, '23', 328)" onmouseover="showTip(event, '23', 328)" class="fn">x</span> <span onmouseout="hideTip(event, '24', 329)" onmouseover="showTip(event, '24', 329)" class="fn">y</span> <span class="o">=</span> <span onmouseout="hideTip(event, '23', 330)" onmouseover="showTip(event, '23', 330)" class="fn">x</span> <span class="o">+</span> <span onmouseout="hideTip(event, '24', 331)" onmouseover="showTip(event, '24', 331)" class="fn">y</span> <span onmouseout="hideTip(event, '78', 332)" onmouseover="showTip(event, '78', 332)" class="fn">map2</span> <span onmouseout="hideTip(event, '22', 333)" onmouseover="showTip(event, '22', 333)" class="fn">add</span> <span class="pn">(</span><span onmouseout="hideTip(event, '66', 334)" onmouseover="showTip(event, '66', 334)" class="uc">Series</span><span class="pn">(</span><span class="n">0</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '68', 335)" onmouseover="showTip(event, '68', 335)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">03</span><span class="pn">)</span><span class="pn">,</span> <span class="n">1</span> <span onmouseout="hideTip(event, '68', 336)" onmouseover="showTip(event, '68', 336)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">05</span><span class="pn">)</span><span class="pn">,</span> <span class="n">5</span> <span class="pn">]</span><span class="pn">)</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '66', 337)" onmouseover="showTip(event, '66', 337)" class="uc">Series</span><span class="pn">(</span><span class="n">2</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '68', 338)" onmouseover="showTip(event, '68', 338)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">03</span><span class="pn">)</span><span class="pn">,</span> <span class="n">2</span> <span onmouseout="hideTip(event, '68', 339)" onmouseover="showTip(event, '68', 339)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">04</span><span class="pn">)</span><span class="pn">,</span> <span class="n">3</span><span class="pn">]</span><span class="pn">)</span><span class="pn">)</span> </code></pre> <table class="pre"><tr><td><pre><code>Series (2, [(10/03/2020 00:00:00, 3); (10/04/2020 00:00:00, 4); (10/05/2020 00:00:00, 8)])</code></pre></td></tr></table> <p>Here is a graphical representation:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="id">Initial</span> <span class="n">2020</span><span class="o">-</span><span class="n">10</span><span class="o">-</span><span class="n">3</span> <span class="n">4</span> <span class="n">5</span> <span class="id">x</span><span class="pn">:</span> <span class="n">0</span> <span class="n">1</span> <span class="o">-</span> <span class="n">5</span> <span class="id">y</span><span class="pn">:</span> <span class="n">2</span> <span class="n">2</span> <span class="n">3</span> <span class="o">-</span> <span class="id">result</span><span class="pn">:</span> <span class="n">2</span> <span class="n">3</span> <span class="n">4</span> <span class="n">8</span> </code></pre> <p>We define <code>apply</code> and the two operators as we did for option:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '93', 340)" onmouseover="showTip(event, '93', 340)" class="fn">apply</span> <span onmouseout="hideTip(event, '94', 341)" onmouseover="showTip(event, '94', 341)" class="fn">f</span> <span onmouseout="hideTip(event, '95', 342)" onmouseover="showTip(event, '95', 342)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '78', 343)" onmouseover="showTip(event, '78', 343)" class="fn">map2</span> <span onmouseout="hideTip(event, '1', 344)" onmouseover="showTip(event, '1', 344)" class="fn">basicApply</span> <span onmouseout="hideTip(event, '94', 345)" onmouseover="showTip(event, '94', 345)" class="fn">f</span> <span onmouseout="hideTip(event, '95', 346)" onmouseover="showTip(event, '95', 346)" class="fn">x</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;!&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '71', 347)" onmouseover="showTip(event, '71', 347)" class="fn">map</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;*&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '93', 348)" onmouseover="showTip(event, '93', 348)" class="fn">apply</span> </code></pre> <p>And we can use it with a user</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '30', 349)" onmouseover="showTip(event, '30', 349)" class="rt">User</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 350)" onmouseover="showTip(event, '64', 350)" class="rt">string</span> <span class="prop">LastName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 351)" onmouseover="showTip(event, '64', 351)" class="rt">string</span> <span class="prop">Age</span><span class="pn">:</span> <span onmouseout="hideTip(event, '26', 352)" onmouseover="showTip(event, '26', 352)" class="vt">int</span> <span class="prop">FavoriteLanguage</span><span class="pn">:</span> <span onmouseout="hideTip(event, '64', 353)" onmouseover="showTip(event, '64', 353)" class="rt">string</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '32', 354)" onmouseover="showTip(event, '32', 354)" class="fn">user</span> <span onmouseout="hideTip(event, '33', 355)" onmouseover="showTip(event, '33', 355)" class="fn">firstname</span> <span onmouseout="hideTip(event, '34', 356)" onmouseover="showTip(event, '34', 356)" class="fn">lastname</span> <span onmouseout="hideTip(event, '35', 357)" onmouseover="showTip(event, '35', 357)" class="fn">age</span> <span onmouseout="hideTip(event, '36', 358)" onmouseover="showTip(event, '36', 358)" class="fn">favoriteLang</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 359)" onmouseover="showTip(event, '33', 359)" class="fn">firstname</span> <span class="prop">LastName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '34', 360)" onmouseover="showTip(event, '34', 360)" class="fn">lastname</span> <span class="prop">Age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '35', 361)" onmouseover="showTip(event, '35', 361)" class="fn">age</span> <span class="prop">FavoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 362)" onmouseover="showTip(event, '36', 362)" class="fn">favoriteLang</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '96', 363)" onmouseover="showTip(event, '96', 363)" class="id">birthDate</span> <span class="o">=</span> <span onmouseout="hideTip(event, '68', 364)" onmouseover="showTip(event, '68', 364)" class="fn">DateTime</span><span class="pn">(</span><span class="n">1978</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">01</span><span class="pn">)</span> <span onmouseout="hideTip(event, '32', 365)" onmouseover="showTip(event, '32', 365)" class="fn">user</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '70', 366)" onmouseover="showTip(event, '70', 366)" class="fn">always</span> <span class="s">&quot;John&quot;</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '66', 367)" onmouseover="showTip(event, '66', 367)" class="uc">Series</span><span class="pn">(</span><span class="s">&quot;Dow&quot;</span><span class="pn">,</span> <span class="pn">[</span> <span onmouseout="hideTip(event, '68', 368)" onmouseover="showTip(event, '68', 368)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2010</span><span class="pn">,</span><span class="n">08</span><span class="pn">,</span><span class="n">17</span><span class="pn">)</span><span class="pn">,</span> <span class="s">&quot;Snow&quot;</span><span class="pn">]</span><span class="pn">)</span> <span class="c">// married</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '66', 369)" onmouseover="showTip(event, '66', 369)" class="uc">Series</span><span class="pn">(</span><span class="n">0</span><span class="pn">,</span> <span class="pn">[</span><span class="k">for</span> <span onmouseout="hideTip(event, '24', 370)" onmouseover="showTip(event, '24', 370)" class="fn">y</span> <span class="k">in</span> <span class="n">1</span> <span class="o">..</span> <span class="n">42</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '96', 371)" onmouseover="showTip(event, '96', 371)" class="id">birthDate</span><span class="pn">.</span><span onmouseout="hideTip(event, '97', 372)" onmouseover="showTip(event, '97', 372)" class="id">AddYears</span><span class="pn">(</span><span onmouseout="hideTip(event, '24', 373)" onmouseover="showTip(event, '24', 373)" class="fn">y</span><span class="pn">)</span><span class="pn">,</span> <span onmouseout="hideTip(event, '24', 374)" onmouseover="showTip(event, '24', 374)" class="fn">y</span> <span class="pn">]</span><span class="pn">)</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '66', 375)" onmouseover="showTip(event, '66', 375)" class="uc">Series</span><span class="pn">(</span><span class="s">&quot;C#&quot;</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '68', 376)" onmouseover="showTip(event, '68', 376)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2005</span><span class="pn">,</span><span class="n">05</span><span class="pn">,</span><span class="n">01</span><span class="pn">)</span><span class="pn">,</span> <span class="s">&quot;F#&quot;</span><span class="pn">]</span><span class="pn">)</span> </code></pre> <p>The result is a <code>Series</code> of <code>User</code> with the new values on each change.</p> <p>We can now take any function that works on non-<code>Series</code> values, and apply it to <code>Series</code> of values. This is especially useful with hotels data. Hotels define prices, availability, closures and all other properties for their rooms for each night in a calendar. Each property can be modeled as a Series.</p> <p>Let's compute the potential sells for a room:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '98', 377)" onmouseover="showTip(event, '98', 377)" class="fn">potentialSells</span> <span onmouseout="hideTip(event, '99', 378)" onmouseover="showTip(event, '99', 378)" class="fn">availability</span> <span onmouseout="hideTip(event, '100', 379)" onmouseover="showTip(event, '100', 379)" class="fn">price</span> <span onmouseout="hideTip(event, '101', 380)" onmouseover="showTip(event, '101', 380)" class="fn">closed</span> <span class="o">=</span> <span class="k">if</span> <span onmouseout="hideTip(event, '101', 381)" onmouseover="showTip(event, '101', 381)" class="fn">closed</span> <span class="k">then</span> <span class="n">0m</span> <span class="k">else</span> <span onmouseout="hideTip(event, '102', 382)" onmouseover="showTip(event, '102', 382)" class="fn">decimal</span> <span onmouseout="hideTip(event, '99', 383)" onmouseover="showTip(event, '99', 383)" class="fn">availability</span> <span class="o">*</span> <span onmouseout="hideTip(event, '100', 384)" onmouseover="showTip(event, '100', 384)" class="fn">price</span> </code></pre> <p>This function has no notion of time and Series.</p> <p>Now we want to apply it for every nights:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '103', 385)" onmouseover="showTip(event, '103', 385)" class="id">availability</span> <span class="o">=</span> <span onmouseout="hideTip(event, '66', 386)" onmouseover="showTip(event, '66', 386)" class="uc">Series</span><span class="pn">(</span><span class="n">0</span><span class="pn">,</span> <span class="pn">[</span> <span onmouseout="hideTip(event, '68', 387)" onmouseover="showTip(event, '68', 387)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">03</span><span class="pn">)</span><span class="pn">,</span> <span class="n">5</span> <span onmouseout="hideTip(event, '68', 388)" onmouseover="showTip(event, '68', 388)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">07</span><span class="pn">)</span><span class="pn">,</span> <span class="n">3</span> <span onmouseout="hideTip(event, '68', 389)" onmouseover="showTip(event, '68', 389)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">09</span><span class="pn">)</span><span class="pn">,</span> <span class="n">0</span><span class="pn">]</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '104', 390)" onmouseover="showTip(event, '104', 390)" class="id">price</span> <span class="o">=</span> <span onmouseout="hideTip(event, '66', 391)" onmouseover="showTip(event, '66', 391)" class="uc">Series</span><span class="pn">(</span><span class="n">100m</span><span class="pn">,</span> <span class="pn">[</span> <span onmouseout="hideTip(event, '68', 392)" onmouseover="showTip(event, '68', 392)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">04</span><span class="pn">)</span><span class="pn">,</span> <span class="n">110m</span> <span onmouseout="hideTip(event, '68', 393)" onmouseover="showTip(event, '68', 393)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">06</span><span class="pn">)</span><span class="pn">,</span> <span class="n">100m</span> <span class="pn">]</span><span class="pn">)</span> <span class="k">let</span> <span onmouseout="hideTip(event, '105', 394)" onmouseover="showTip(event, '105', 394)" class="id">closed</span> <span class="o">=</span> <span onmouseout="hideTip(event, '66', 395)" onmouseover="showTip(event, '66', 395)" class="uc">Series</span><span class="pn">(</span><span class="k">false</span><span class="pn">,</span> <span class="pn">[</span><span onmouseout="hideTip(event, '68', 396)" onmouseover="showTip(event, '68', 396)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">5</span><span class="pn">)</span><span class="pn">,</span> <span class="k">true</span> <span onmouseout="hideTip(event, '68', 397)" onmouseover="showTip(event, '68', 397)" class="fn">DateTime</span><span class="pn">(</span><span class="n">2020</span><span class="pn">,</span><span class="n">10</span><span class="pn">,</span><span class="n">6</span><span class="pn">)</span><span class="pn">,</span> <span class="k">false</span><span class="pn">]</span><span class="pn">)</span> <span onmouseout="hideTip(event, '98', 398)" onmouseover="showTip(event, '98', 398)" class="fn">potentialSells</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '103', 399)" onmouseover="showTip(event, '103', 399)" class="id">availability</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '104', 400)" onmouseover="showTip(event, '104', 400)" class="id">price</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '105', 401)" onmouseover="showTip(event, '105', 401)" class="id">closed</span> </code></pre> <table class="pre"><tr><td><pre><code>Series (0M, [(10/03/2020 00:00:00, 500M); (10/04/2020 00:00:00, 550M); (10/05/2020 00:00:00, 0M); (10/06/2020 00:00:00, 500M); (10/07/2020 00:00:00, 300M); (10/09/2020 00:00:00, 0M)])</code></pre></td></tr></table> <p>Just imagine the headache if we did not have this applicative..</p> <h2><a name="Queries" class="anchor" href="#Queries">Queries</a></h2> <p>The first two examples were structures that "contain" data. For this third case, we'll consider a different problem.</p> <p>We have a document store - like elastic search - where we can query documents and request specific properties for the returned document. For instance in the query for a user we ask for the "firstname", "lastname" and "age" properties and we get these properties in the result.</p> <p>For the demo we'll use a simple function:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '107', 403)" onmouseover="showTip(event, '107', 403)" class="fn">queryService</span> <span class="pn">(</span><span onmouseout="hideTip(event, '108', 404)" onmouseover="showTip(event, '108', 404)" class="fn">properties</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 405)" onmouseover="showTip(event, '31', 405)" class="rt">string</span> <span onmouseout="hideTip(event, '109', 406)" onmouseover="showTip(event, '109', 406)" class="rt">Set</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '110', 407)" onmouseover="showTip(event, '110', 407)" class="rt">Map</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '31', 408)" onmouseover="showTip(event, '31', 408)" class="rt">string</span><span class="pn">,</span><span onmouseout="hideTip(event, '31', 409)" onmouseover="showTip(event, '31', 409)" class="rt">string</span><span class="pn">&gt;</span> <span class="o">=</span> <span onmouseout="hideTip(event, '110', 410)" onmouseover="showTip(event, '110', 410)" class="m">Map</span><span class="pn">.</span><span onmouseout="hideTip(event, '111', 411)" onmouseover="showTip(event, '111', 411)" class="id">ofList</span> <span class="pn">[</span> <span class="k">if</span> <span onmouseout="hideTip(event, '109', 412)" onmouseover="showTip(event, '109', 412)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '112', 413)" onmouseover="showTip(event, '112', 413)" class="id">contains</span> <span class="s">&quot;firstname&quot;</span> <span onmouseout="hideTip(event, '108', 414)" onmouseover="showTip(event, '108', 414)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;firstname&quot;</span><span class="pn">,</span> <span class="s">&quot;John&quot;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '109', 415)" onmouseover="showTip(event, '109', 415)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '112', 416)" onmouseover="showTip(event, '112', 416)" class="id">contains</span> <span class="s">&quot;lastname&quot;</span> <span onmouseout="hideTip(event, '108', 417)" onmouseover="showTip(event, '108', 417)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;lastname&quot;</span><span class="pn">,</span> <span class="s">&quot;Doe&quot;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '109', 418)" onmouseover="showTip(event, '109', 418)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '112', 419)" onmouseover="showTip(event, '112', 419)" class="id">contains</span> <span class="s">&quot;age&quot;</span> <span onmouseout="hideTip(event, '108', 420)" onmouseover="showTip(event, '108', 420)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;age&quot;</span><span class="pn">,</span> <span class="s">&quot;42&quot;</span> <span class="k">if</span> <span onmouseout="hideTip(event, '109', 421)" onmouseover="showTip(event, '109', 421)" class="m">Set</span><span class="pn">.</span><span onmouseout="hideTip(event, '112', 422)" onmouseover="showTip(event, '112', 422)" class="id">contains</span> <span class="s">&quot;favoritelanguage&quot;</span> <span onmouseout="hideTip(event, '108', 423)" onmouseover="showTip(event, '108', 423)" class="fn">properties</span> <span class="k">then</span> <span class="s">&quot;favoritelanguage&quot;</span><span class="pn">,</span> <span class="s">&quot;F#&quot;</span> <span class="pn">]</span> </code></pre> <p>The real one would take a document id and actually call the document database.</p> <p>Despite being very useful (we get only the properties we're interested in), this kind of interface often leads to irritating bugs. When accessing the result, we must be sure that all the properties we use have been correctly requested. And when we stop using a property, we should not forget to remove it from the query.</p> <p>That would be awesome if we could just use the properties and the query would magically know which one to fetch.</p> <p>Let's introduce the Query type:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '113', 424)" onmouseover="showTip(event, '113', 424)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '5', 425)" onmouseover="showTip(event, '5', 425)" class="id">t</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 426)" onmouseover="showTip(event, '31', 426)" class="rt">string</span> <span onmouseout="hideTip(event, '109', 427)" onmouseover="showTip(event, '109', 427)" class="rt">Set</span> <span class="fn">Get</span><span class="pn">:</span> <span onmouseout="hideTip(event, '110', 428)" onmouseover="showTip(event, '110', 428)" class="rt">Map</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '31', 429)" onmouseover="showTip(event, '31', 429)" class="rt">string</span><span class="pn">,</span><span onmouseout="hideTip(event, '31', 430)" onmouseover="showTip(event, '31', 430)" class="rt">string</span><span class="pn">&gt;</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '5', 431)" onmouseover="showTip(event, '5', 431)" class="id">t</span> <span class="pn">}</span> </code></pre> <p>This type is exactly here to do what we want. It contains a list of properties to query and a function that uses the result to extract a value from it. We have to create simple ways to build it safely.</p> <p>The first thing is to be able to query a single property</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '114', 432)" onmouseover="showTip(event, '114', 432)" class="fn">prop</span> <span onmouseout="hideTip(event, '115', 433)" onmouseover="showTip(event, '115', 433)" class="fn">name</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '113', 434)" onmouseover="showTip(event, '113', 434)" class="rt">Query</span><span class="pn">&lt;</span><span onmouseout="hideTip(event, '31', 435)" onmouseover="showTip(event, '31', 435)" class="rt">string</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span> <span class="o">=</span> <span onmouseout="hideTip(event, '116', 436)" onmouseover="showTip(event, '116', 436)" class="fn">set</span> <span class="pn">[</span> <span onmouseout="hideTip(event, '115', 437)" onmouseover="showTip(event, '115', 437)" class="fn">name</span> <span class="pn">]</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '117', 438)" onmouseover="showTip(event, '117', 438)" class="fn">response</span> <span class="k">-&gt;</span> <span onmouseout="hideTip(event, '117', 439)" onmouseover="showTip(event, '117', 439)" class="fn">response</span><span class="pn">.</span><span class="pn">[</span><span onmouseout="hideTip(event, '115', 440)" onmouseover="showTip(event, '115', 440)" class="fn">name</span><span class="pn">]</span> <span class="pn">}</span> </code></pre> <p>This function takes a property name and builds a Query that:</p> <ul> <li>has the expected property name in <code>Properties</code></li> <li>can extract this property from the result</li> </ul> <p>We can define stock properties like using the <code>prop</code> function:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '118', 441)" onmouseover="showTip(event, '118', 441)" class="id">firstname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '114', 442)" onmouseover="showTip(event, '114', 442)" class="fn">prop</span> <span class="s">&quot;firstname&quot;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '119', 443)" onmouseover="showTip(event, '119', 443)" class="id">lastname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '114', 444)" onmouseover="showTip(event, '114', 444)" class="fn">prop</span> <span class="s">&quot;lastname&quot;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '120', 445)" onmouseover="showTip(event, '120', 445)" class="id">favoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '114', 446)" onmouseover="showTip(event, '114', 446)" class="fn">prop</span> <span class="s">&quot;favoritelanguage&quot;</span> </code></pre> <p>We can fetch them with the following function:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '121', 447)" onmouseover="showTip(event, '121', 447)" class="fn">callService</span> <span class="pn">(</span><span onmouseout="hideTip(event, '122', 448)" onmouseover="showTip(event, '122', 448)" class="fn">query</span><span class="pn">:</span> <span onmouseout="hideTip(event, '113', 449)" onmouseover="showTip(event, '113', 449)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '5', 450)" onmouseover="showTip(event, '5', 450)" class="id">t</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '5', 451)" onmouseover="showTip(event, '5', 451)" class="id">t</span> <span class="o">=</span> <span class="k">let</span> <span onmouseout="hideTip(event, '117', 452)" onmouseover="showTip(event, '117', 452)" class="fn">response</span> <span class="o">=</span> <span onmouseout="hideTip(event, '107', 453)" onmouseover="showTip(event, '107', 453)" class="fn">queryService</span> <span onmouseout="hideTip(event, '122', 454)" onmouseover="showTip(event, '122', 454)" class="fn">query</span><span class="pn">.</span><span onmouseout="hideTip(event, '123', 455)" onmouseover="showTip(event, '123', 455)" class="id">Properties</span> <span onmouseout="hideTip(event, '122', 456)" onmouseover="showTip(event, '122', 456)" class="fn">query</span><span class="pn">.</span><span onmouseout="hideTip(event, '124', 457)" onmouseover="showTip(event, '124', 457)" class="id">Get</span> <span onmouseout="hideTip(event, '117', 458)" onmouseover="showTip(event, '117', 458)" class="fn">response</span> </code></pre> <p>For <code>age</code>, we'd like to convert it to an int. This is easily done with a <code>map</code> function that will change the result using a given function</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '125', 459)" onmouseover="showTip(event, '125', 459)" class="fn">map</span> <span class="pn">(</span><span onmouseout="hideTip(event, '2', 460)" onmouseover="showTip(event, '2', 460)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 461)" onmouseover="showTip(event, '9', 461)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 462)" onmouseover="showTip(event, '10', 462)" class="id">b</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '126', 463)" onmouseover="showTip(event, '126', 463)" class="fn">q</span><span class="pn">:</span> <span onmouseout="hideTip(event, '113', 464)" onmouseover="showTip(event, '113', 464)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 465)" onmouseover="showTip(event, '9', 465)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '113', 466)" onmouseover="showTip(event, '113', 466)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 467)" onmouseover="showTip(event, '10', 467)" class="id">b</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span> <span class="o">=</span> <span onmouseout="hideTip(event, '126', 468)" onmouseover="showTip(event, '126', 468)" class="fn">q</span><span class="pn">.</span><span onmouseout="hideTip(event, '123', 469)" onmouseover="showTip(event, '123', 469)" class="id">Properties</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '117', 470)" onmouseover="showTip(event, '117', 470)" class="fn">response</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '77', 471)" onmouseover="showTip(event, '77', 471)" class="fn">v</span> <span class="o">=</span> <span onmouseout="hideTip(event, '126', 472)" onmouseover="showTip(event, '126', 472)" class="fn">q</span><span class="pn">.</span><span onmouseout="hideTip(event, '127', 473)" onmouseover="showTip(event, '127', 473)" class="id">Get</span> <span onmouseout="hideTip(event, '117', 474)" onmouseover="showTip(event, '117', 474)" class="fn">response</span> <span onmouseout="hideTip(event, '2', 475)" onmouseover="showTip(event, '2', 475)" class="fn">f</span> <span onmouseout="hideTip(event, '77', 476)" onmouseover="showTip(event, '77', 476)" class="fn">v</span> <span class="pn">}</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;!&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '125', 477)" onmouseover="showTip(event, '125', 477)" class="fn">map</span> <span class="k">let</span> <span onmouseout="hideTip(event, '128', 478)" onmouseover="showTip(event, '128', 478)" class="id">age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '26', 479)" onmouseover="showTip(event, '26', 479)" class="fn">int</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '114', 480)" onmouseover="showTip(event, '114', 480)" class="fn">prop</span> <span class="s">&quot;age&quot;</span> </code></pre> <p>Building a full name could be done like that (it can be <a href="https://shinesolutions.com/2018/01/08/falsehoods-programmers-believe-about-names-with-examples/">more complicated</a>):</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '129', 481)" onmouseover="showTip(event, '129', 481)" class="fn">fullname</span> <span onmouseout="hideTip(event, '33', 482)" onmouseover="showTip(event, '33', 482)" class="fn">firstname</span> <span onmouseout="hideTip(event, '34', 483)" onmouseover="showTip(event, '34', 483)" class="fn">lastname</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 484)" onmouseover="showTip(event, '33', 484)" class="fn">firstname</span> <span class="o">+</span> <span class="s">&quot; &quot;</span> <span class="o">+</span> <span onmouseout="hideTip(event, '34', 485)" onmouseover="showTip(event, '34', 485)" class="fn">lastname</span> </code></pre> <p>We need to retrieve both first name and last name and pass them to the function. But we can also make a <code>map2</code>:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '130', 486)" onmouseover="showTip(event, '130', 486)" class="fn">map2</span> <span class="pn">(</span><span onmouseout="hideTip(event, '17', 487)" onmouseover="showTip(event, '17', 487)" class="fn">f</span><span class="pn">:</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 488)" onmouseover="showTip(event, '9', 488)" class="id">a</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 489)" onmouseover="showTip(event, '10', 489)" class="id">b</span> <span class="k">-&gt;</span> <span class="ta">&#39;</span><span onmouseout="hideTip(event, '18', 490)" onmouseover="showTip(event, '18', 490)" class="id">c</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '131', 491)" onmouseover="showTip(event, '131', 491)" class="fn">x</span><span class="pn">:</span> <span onmouseout="hideTip(event, '113', 492)" onmouseover="showTip(event, '113', 492)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '9', 493)" onmouseover="showTip(event, '9', 493)" class="id">a</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">(</span><span onmouseout="hideTip(event, '132', 494)" onmouseover="showTip(event, '132', 494)" class="fn">y</span><span class="pn">:</span> <span onmouseout="hideTip(event, '113', 495)" onmouseover="showTip(event, '113', 495)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '10', 496)" onmouseover="showTip(event, '10', 496)" class="id">b</span><span class="pn">&gt;</span><span class="pn">)</span> <span class="pn">:</span> <span onmouseout="hideTip(event, '113', 497)" onmouseover="showTip(event, '113', 497)" class="rt">Query</span><span class="pn">&lt;</span><span class="ta">&#39;</span><span onmouseout="hideTip(event, '18', 498)" onmouseover="showTip(event, '18', 498)" class="id">c</span><span class="pn">&gt;</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">Properties</span> <span class="o">=</span> <span onmouseout="hideTip(event, '131', 499)" onmouseover="showTip(event, '131', 499)" class="fn">x</span><span class="pn">.</span><span onmouseout="hideTip(event, '123', 500)" onmouseover="showTip(event, '123', 500)" class="id">Properties</span> <span class="o">+</span> <span onmouseout="hideTip(event, '132', 501)" onmouseover="showTip(event, '132', 501)" class="fn">y</span><span class="pn">.</span><span onmouseout="hideTip(event, '123', 502)" onmouseover="showTip(event, '123', 502)" class="id">Properties</span> <span class="fn">Get</span> <span class="o">=</span> <span class="k">fun</span> <span onmouseout="hideTip(event, '117', 503)" onmouseover="showTip(event, '117', 503)" class="fn">response</span> <span class="k">-&gt;</span> <span class="k">let</span> <span onmouseout="hideTip(event, '20', 504)" onmouseover="showTip(event, '20', 504)" class="fn">xvalue</span> <span class="o">=</span> <span onmouseout="hideTip(event, '131', 505)" onmouseover="showTip(event, '131', 505)" class="fn">x</span><span class="pn">.</span><span onmouseout="hideTip(event, '127', 506)" onmouseover="showTip(event, '127', 506)" class="id">Get</span> <span onmouseout="hideTip(event, '117', 507)" onmouseover="showTip(event, '117', 507)" class="fn">response</span> <span class="k">let</span> <span onmouseout="hideTip(event, '21', 508)" onmouseover="showTip(event, '21', 508)" class="fn">yvalue</span> <span class="o">=</span> <span onmouseout="hideTip(event, '132', 509)" onmouseover="showTip(event, '132', 509)" class="fn">y</span><span class="pn">.</span><span onmouseout="hideTip(event, '133', 510)" onmouseover="showTip(event, '133', 510)" class="id">Get</span> <span onmouseout="hideTip(event, '117', 511)" onmouseover="showTip(event, '117', 511)" class="fn">response</span> <span onmouseout="hideTip(event, '17', 512)" onmouseover="showTip(event, '17', 512)" class="fn">f</span> <span onmouseout="hideTip(event, '20', 513)" onmouseover="showTip(event, '20', 513)" class="fn">xvalue</span> <span onmouseout="hideTip(event, '21', 514)" onmouseover="showTip(event, '21', 514)" class="fn">yvalue</span> <span class="pn">}</span> </code></pre> <p>The result is a Query that:</p> <ul> <li>has the union of the properties of both queries</li> <li>gets values from both and passes them to the given function</li> </ul> <p>With a <code>map2</code>, we can define <code>apply</code> and the operator:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">let</span> <span onmouseout="hideTip(event, '134', 515)" onmouseover="showTip(event, '134', 515)" class="fn">apply</span> <span onmouseout="hideTip(event, '135', 516)" onmouseover="showTip(event, '135', 516)" class="fn">f</span> <span onmouseout="hideTip(event, '131', 517)" onmouseover="showTip(event, '131', 517)" class="fn">x</span> <span class="o">=</span> <span onmouseout="hideTip(event, '130', 518)" onmouseover="showTip(event, '130', 518)" class="fn">map2</span> <span onmouseout="hideTip(event, '1', 519)" onmouseover="showTip(event, '1', 519)" class="fn">basicApply</span> <span onmouseout="hideTip(event, '135', 520)" onmouseover="showTip(event, '135', 520)" class="fn">f</span> <span onmouseout="hideTip(event, '131', 521)" onmouseover="showTip(event, '131', 521)" class="fn">x</span> <span class="k">let</span> <span class="pn">(</span><span class="o">&lt;*&gt;</span><span class="pn">)</span> <span class="o">=</span> <span onmouseout="hideTip(event, '134', 522)" onmouseover="showTip(event, '134', 522)" class="fn">apply</span> </code></pre> <p>With this we can query a user:</p> <pre class="fssnip highlighted"><code lang="fsharp"> <span class="k">type</span> <span onmouseout="hideTip(event, '30', 523)" onmouseover="showTip(event, '30', 523)" class="rt">User</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 524)" onmouseover="showTip(event, '31', 524)" class="rt">string</span> <span class="prop">LastName</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 525)" onmouseover="showTip(event, '31', 525)" class="rt">string</span> <span class="prop">Age</span><span class="pn">:</span> <span onmouseout="hideTip(event, '26', 526)" onmouseover="showTip(event, '26', 526)" class="vt">int</span> <span class="prop">FavoriteLanguage</span><span class="pn">:</span> <span onmouseout="hideTip(event, '31', 527)" onmouseover="showTip(event, '31', 527)" class="rt">string</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '32', 528)" onmouseover="showTip(event, '32', 528)" class="fn">user</span> <span onmouseout="hideTip(event, '33', 529)" onmouseover="showTip(event, '33', 529)" class="fn">firstname</span> <span onmouseout="hideTip(event, '34', 530)" onmouseover="showTip(event, '34', 530)" class="fn">lastname</span> <span onmouseout="hideTip(event, '35', 531)" onmouseover="showTip(event, '35', 531)" class="fn">age</span> <span onmouseout="hideTip(event, '36', 532)" onmouseover="showTip(event, '36', 532)" class="fn">favoriteLang</span> <span class="o">=</span> <span class="pn">{</span> <span class="prop">FirstName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '33', 533)" onmouseover="showTip(event, '33', 533)" class="fn">firstname</span> <span class="prop">LastName</span> <span class="o">=</span> <span onmouseout="hideTip(event, '34', 534)" onmouseover="showTip(event, '34', 534)" class="fn">lastname</span> <span class="prop">Age</span> <span class="o">=</span> <span onmouseout="hideTip(event, '35', 535)" onmouseover="showTip(event, '35', 535)" class="fn">age</span> <span class="prop">FavoriteLanguage</span> <span class="o">=</span> <span onmouseout="hideTip(event, '36', 536)" onmouseover="showTip(event, '36', 536)" class="fn">favoriteLang</span> <span class="pn">}</span> <span class="k">let</span> <span onmouseout="hideTip(event, '136', 537)" onmouseover="showTip(event, '136', 537)" class="id">userQuery</span> <span class="o">=</span> <span onmouseout="hideTip(event, '32', 538)" onmouseover="showTip(event, '32', 538)" class="fn">user</span> <span class="o">&lt;!&gt;</span> <span onmouseout="hideTip(event, '118', 539)" onmouseover="showTip(event, '118', 539)" class="id">firstname</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '119', 540)" onmouseover="showTip(event, '119', 540)" class="id">lastname</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '128', 541)" onmouseover="showTip(event, '128', 541)" class="id">age</span> <span class="o">&lt;*&gt;</span> <span onmouseout="hideTip(event, '120', 542)" onmouseover="showTip(event, '120', 542)" class="id">favoriteLanguage</span> <span onmouseout="hideTip(event, '121', 543)" onmouseover="showTip(event, '121', 543)" class="fn">callService</span> <span onmouseout="hideTip(event, '136', 544)" onmouseover="showTip(event, '136', 544)" class="id">userQuery</span> </code></pre> <p>using <code>userQuery</code>, we just composed basic properties to form a query for a larger structure, so we know that we cannot use a property without requesting it in the query.</p> <h2><a name="Other-applicatives" class="anchor" href="#Other-applicatives">Other applicatives</a></h2> <p>Applicatives can be found in a lot of places. To zip lists, execute async computations in parallel.</p> <p>It can also be used to create formlets. A <code>Formlet&lt;'t&gt;</code> is a UX form to fill a <code>'t</code> structure. The simples formlet are input fields. A text input is a <code>Formlet&lt;string&gt;</code>, a checkbox a <code>Formlet&lt;bool&gt;</code>. A label function is a <code>(string -&gt; Formlet&lt;'a&gt; -&gt; Formlet&lt;'a&gt;)</code> function that adds a label to an existing formlet. A <code>map</code> function can change <code>Formlet&lt;string&gt;</code> to <code>Formlet&lt;Address&gt;</code> given a <code>(string -&gt; Address)</code> function. And we use <code>map2</code> and <code>apply</code> to take several formlets and compose them in a <code>Formlet&lt;User&gt;</code> for instance.</p> <p>Once you start to see it, you'll spot them everywhere.</p> <p>Be careful to not abuse it. For a single use, it's often better to compute the result directly.</p> <p>But when you have many places that are impacted, especially if the code changes often, it can reduce code complexity by a fair amount.</p> <p>Don't hesitate to ping me <a href="https://twitter.com/thinkbeforecoding">on twitter</a> if you find nice uses of applicatives!</p> <p><em>As suggested by <a href="https://twitter.com/ChetHusk">Chet Husk</a>, I'll soon post about the new Applicatives support in Computation Expressions.</em></p> <div class="fsdocs-tip" id="1">val basicApply: f: (&#39;a -&gt; &#39;b) -&gt; x: &#39;a -&gt; &#39;b</div> <div class="fsdocs-tip" id="2">val f: (&#39;a -&gt; &#39;b)</div> <div class="fsdocs-tip" id="3">val x: &#39;a</div> <div class="fsdocs-tip" id="4">Multiple items<br />module Option from Microsoft.FSharp.Core<br /><br />--------------------<br />type Option&lt;&#39;t&gt; = | Some of &#39;t | None</div> <div class="fsdocs-tip" id="5">&#39;t</div> <div class="fsdocs-tip" id="6">union case Option.Some: Value: &#39;T -&gt; Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="7">union case Option.None: Option&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="8">val map: f: (&#39;a -&gt; &#39;b) -&gt; x: Option&lt;&#39;a&gt; -&gt; Option&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="9">&#39;a</div> <div class="fsdocs-tip" id="10">&#39;b</div> <div class="fsdocs-tip" id="11">val x: Option&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="12">union case Option.Some: &#39;t -&gt; Option&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="13">val value: &#39;a</div> <div class="fsdocs-tip" id="14">union case Option.None: Option&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="15">module Option from Microsoft.FSharp.Core</div> <div class="fsdocs-tip" id="16">val map2: f: (&#39;a -&gt; &#39;b -&gt; &#39;c) -&gt; x: Option&lt;&#39;a&gt; -&gt; y: Option&lt;&#39;b&gt; -&gt; Option&lt;&#39;c&gt;</div> <div class="fsdocs-tip" id="17">val f: (&#39;a -&gt; &#39;b -&gt; &#39;c)</div> <div class="fsdocs-tip" id="18">&#39;c</div> <div class="fsdocs-tip" id="19">val y: Option&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="20">val xvalue: &#39;a</div> <div class="fsdocs-tip" id="21">val yvalue: &#39;b</div> <div class="fsdocs-tip" id="22">val add: x: int -&gt; y: int -&gt; int</div> <div class="fsdocs-tip" id="23">val x: int</div> <div class="fsdocs-tip" id="24">val y: int</div> <div class="fsdocs-tip" id="25">val mappedAdd: (Option&lt;int&gt; -&gt; Option&lt;(int -&gt; int)&gt;)</div> <div class="fsdocs-tip" id="26">Multiple items<br />val int: value: &#39;T -&gt; int (requires member op_Explicit)<br /><br />--------------------<br />type int = int32<br /><br />--------------------<br />type int&lt;&#39;Measure&gt; = int</div> <div class="fsdocs-tip" id="27">val apply: f: Option&lt;(&#39;a -&gt; &#39;b)&gt; -&gt; x: Option&lt;&#39;a&gt; -&gt; Option&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="28">val f: Option&lt;(&#39;a -&gt; &#39;b)&gt;</div> <div class="fsdocs-tip" id="29">val partialAdd: Option&lt;(int -&gt; int)&gt;</div> <div class="fsdocs-tip" id="30">type User = { FirstName: string LastName: string Age: int FavoriteLanguage: string }</div> <div class="fsdocs-tip" id="31">Multiple items<br />val string: value: &#39;T -&gt; string<br /><br />--------------------<br />type string = System.String</div> <div class="fsdocs-tip" id="32">val user: firstname: string -&gt; lastname: string -&gt; age: int -&gt; favoriteLang: string -&gt; User</div> <div class="fsdocs-tip" id="33">val firstname: string</div> <div class="fsdocs-tip" id="34">val lastname: string</div> <div class="fsdocs-tip" id="35">val age: int</div> <div class="fsdocs-tip" id="36">val favoriteLang: string</div> <div class="fsdocs-tip" id="37">val user&#39;: Option&lt;(string -&gt; int -&gt; string -&gt; User)&gt;</div> <div class="fsdocs-tip" id="38">val user&#39;&#39;: Option&lt;(int -&gt; string -&gt; User)&gt;</div> <div class="fsdocs-tip" id="39">val user&#39;&#39;&#39;: Option&lt;(string -&gt; User)&gt;</div> <div class="fsdocs-tip" id="40">val map2: f: (&#39;a -&gt; &#39;b -&gt; &#39;c) -&gt; xresult: Result&lt;&#39;a,string&gt; -&gt; yresult: Result&lt;&#39;b,string&gt; -&gt; Result&lt;&#39;c,string&gt;</div> <div class="fsdocs-tip" id="41">val xresult: Result&lt;&#39;a,string&gt;</div> <div class="fsdocs-tip" id="42">Multiple items<br />module Result from Microsoft.FSharp.Core<br /><br />--------------------<br />[&lt;Struct&gt;] type Result&lt;&#39;T,&#39;TError&gt; = | Ok of ResultValue: &#39;T | Error of ErrorValue: &#39;TError member Equals: Result&lt;&#39;T,&#39;TError&gt; * IEqualityComparer -&gt; bool member IsError: bool member IsOk: bool</div> <div class="fsdocs-tip" id="43">val yresult: Result&lt;&#39;b,string&gt;</div> <div class="fsdocs-tip" id="44">union case Result.Ok: ResultValue: &#39;T -&gt; Result&lt;&#39;T,&#39;TError&gt;</div> <div class="fsdocs-tip" id="45">val y: &#39;b</div> <div class="fsdocs-tip" id="46">union case Result.Error: ErrorValue: &#39;TError -&gt; Result&lt;&#39;T,&#39;TError&gt;</div> <div class="fsdocs-tip" id="47">val fe: string</div> <div class="fsdocs-tip" id="48">val xe: string</div> <div class="fsdocs-tip" id="49">val apply: f: Result&lt;(&#39;a -&gt; &#39;b),string&gt; -&gt; x: Result&lt;&#39;a,string&gt; -&gt; Result&lt;&#39;b,string&gt;</div> <div class="fsdocs-tip" id="50">val f: Result&lt;(&#39;a -&gt; &#39;b),string&gt;</div> <div class="fsdocs-tip" id="51">val x: Result&lt;&#39;a,string&gt;</div> <div class="fsdocs-tip" id="52">val map: mapping: (&#39;T -&gt; &#39;U) -&gt; result: Result&lt;&#39;T,&#39;TError&gt; -&gt; Result&lt;&#39;U,&#39;TError&gt;</div> <div class="fsdocs-tip" id="53">namespace System</div> <div class="fsdocs-tip" id="54">val notEmpty: prop: string -&gt; value: string -&gt; Result&lt;string,string&gt;</div> <div class="fsdocs-tip" id="55">val prop: string</div> <div class="fsdocs-tip" id="56">val value: string</div> <div class="fsdocs-tip" id="57">Multiple items<br />type String = interface IEnumerable&lt;char&gt; interface IEnumerable interface ICloneable interface IComparable interface IComparable&lt;string&gt; interface IConvertible interface IEquatable&lt;string&gt; interface IParsable&lt;string&gt; interface ISpanParsable&lt;string&gt; new: value: nativeptr&lt;char&gt; -&gt; unit + 8 overloads ...<br /><em>&lt;summary&gt;Represents text as a sequence of UTF-16 code units.&lt;/summary&gt;</em><br /><br />--------------------<br />String(value: nativeptr&lt;char&gt;) : String<br />String(value: char array) : String<br />String(value: ReadOnlySpan&lt;char&gt;) : String<br />String(value: nativeptr&lt;sbyte&gt;) : String<br />String(c: char, count: int) : String<br />String(value: nativeptr&lt;char&gt;, startIndex: int, length: int) : String<br />String(value: char array, startIndex: int, length: int) : String<br />String(value: nativeptr&lt;sbyte&gt;, startIndex: int, length: int) : String<br />String(value: nativeptr&lt;sbyte&gt;, startIndex: int, length: int, enc: Text.Encoding) : String</div> <div class="fsdocs-tip" id="58">String.IsNullOrEmpty(value: string) : bool</div> <div class="fsdocs-tip" id="59">val sprintf: format: Printf.StringFormat&lt;&#39;T&gt; -&gt; &#39;T</div> <div class="fsdocs-tip" id="60">val tryParse: prop: string -&gt; input: string -&gt; Result&lt;int,string&gt;</div> <div class="fsdocs-tip" id="61">val input: string</div> <div class="fsdocs-tip" id="62">[&lt;Struct&gt;] type Int32 = member CompareTo: value: int -&gt; int + 1 overload member Equals: obj: int -&gt; bool + 1 overload member GetHashCode: unit -&gt; int member GetTypeCode: unit -&gt; TypeCode member ToString: unit -&gt; string + 3 overloads member TryFormat: utf8Destination: Span&lt;byte&gt; * bytesWritten: byref&lt;int&gt; * ?format: ReadOnlySpan&lt;char&gt; * ?provider: IFormatProvider -&gt; bool + 1 overload static member Abs: value: int -&gt; int static member BigMul: left: int * right: int -&gt; int64 static member Clamp: value: int * min: int * max: int -&gt; int static member CopySign: value: int * sign: int -&gt; int ...<br /><em>&lt;summary&gt;Represents a 32-bit signed integer.&lt;/summary&gt;</em></div> <div class="fsdocs-tip" id="63">Int32.TryParse(s: string, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(s: ReadOnlySpan&lt;char&gt;, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(utf8Text: ReadOnlySpan&lt;byte&gt;, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(s: string, provider: IFormatProvider, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(s: ReadOnlySpan&lt;char&gt;, provider: IFormatProvider, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(utf8Text: ReadOnlySpan&lt;byte&gt;, provider: IFormatProvider, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(s: string, style: Globalization.NumberStyles, provider: IFormatProvider, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(s: ReadOnlySpan&lt;char&gt;, style: Globalization.NumberStyles, provider: IFormatProvider, result: byref&lt;int&gt;) : bool<br />Int32.TryParse(utf8Text: ReadOnlySpan&lt;byte&gt;, style: Globalization.NumberStyles, provider: IFormatProvider, result: byref&lt;int&gt;) : bool</div> <div class="fsdocs-tip" id="64">Multiple items<br />val string: value: &#39;T -&gt; string<br /><br />--------------------<br />type string = String</div> <div class="fsdocs-tip" id="65">val value: int</div> <div class="fsdocs-tip" id="66">Multiple items<br />union case Series.Series: &#39;a * (DateTime * &#39;a) list -&gt; Series&lt;&#39;a&gt;<br /><br />--------------------<br />type Series&lt;&#39;a&gt; = | Series of &#39;a * (DateTime * &#39;a) list</div> <div class="fsdocs-tip" id="67">type Series&lt;&#39;a&gt; = | Series of &#39;a * (DateTime * &#39;a) list</div> <div class="fsdocs-tip" id="68">Multiple items<br />[&lt;Struct&gt;] type DateTime = new: date: DateOnly * time: TimeOnly -&gt; unit + 16 overloads member Add: value: TimeSpan -&gt; DateTime member AddDays: value: float -&gt; DateTime member AddHours: value: float -&gt; DateTime member AddMicroseconds: value: float -&gt; DateTime member AddMilliseconds: value: float -&gt; DateTime member AddMinutes: value: float -&gt; DateTime member AddMonths: months: int -&gt; DateTime member AddSeconds: value: float -&gt; DateTime member AddTicks: value: int64 -&gt; DateTime ...<br /><em>&lt;summary&gt;Represents an instant in time, typically expressed as a date and time of day.&lt;/summary&gt;</em><br /><br />--------------------<br />DateTime ()<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(ticks: int64) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(date: DateOnly, time: TimeOnly) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(ticks: int64, kind: DateTimeKind) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(date: DateOnly, time: TimeOnly, kind: DateTimeKind) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(year: int, month: int, day: int) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em><br />DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : DateTime<br />&#160;&#160;&#160;<em>(+0 other overloads)</em></div> <div class="fsdocs-tip" id="69">type &#39;T list = List&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="70">val always: x: &#39;a -&gt; Series&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="71">val map: f: (&#39;a -&gt; &#39;b) -&gt; Series&lt;&#39;a&gt; -&gt; Series&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="72">val initial: &#39;a</div> <div class="fsdocs-tip" id="73">val changes: (DateTime * &#39;a) list</div> <div class="fsdocs-tip" id="74">Multiple items<br />module List from Microsoft.FSharp.Collections<br /><br />--------------------<br />type List&lt;&#39;T&gt; = | op_Nil | op_ColonColon of Head: &#39;T * Tail: &#39;T list interface IReadOnlyList&lt;&#39;T&gt; interface IReadOnlyCollection&lt;&#39;T&gt; interface IEnumerable interface IEnumerable&lt;&#39;T&gt; member Equals: List&lt;&#39;T&gt; * IEqualityComparer -&gt; bool member GetReverseIndex: rank: int * offset: int -&gt; int member GetSlice: startIndex: int option * endIndex: int option -&gt; &#39;T list static member Cons: head: &#39;T * tail: &#39;T list -&gt; &#39;T list member Head: &#39;T member IsEmpty: bool ...</div> <div class="fsdocs-tip" id="75">val map: mapping: (&#39;T -&gt; &#39;U) -&gt; list: &#39;T list -&gt; &#39;U list</div> <div class="fsdocs-tip" id="76">val d: DateTime</div> <div class="fsdocs-tip" id="77">val v: &#39;a</div> <div class="fsdocs-tip" id="78">val map2: f: (&#39;a -&gt; &#39;b -&gt; &#39;c) -&gt; Series&lt;&#39;a&gt; -&gt; Series&lt;&#39;b&gt; -&gt; Series&lt;&#39;c&gt;</div> <div class="fsdocs-tip" id="79">val ix: &#39;a</div> <div class="fsdocs-tip" id="80">val cx: (DateTime * &#39;a) list</div> <div class="fsdocs-tip" id="81">val iy: &#39;b</div> <div class="fsdocs-tip" id="82">val cy: (DateTime * &#39;b) list</div> <div class="fsdocs-tip" id="83">val zip: lastx: &#39;a -&gt; lasty: &#39;b -&gt; changesx: (&#39;d * &#39;a) list -&gt; changesy: (&#39;d * &#39;b) list -&gt; (&#39;d * &#39;c) list (requires comparison)</div> <div class="fsdocs-tip" id="84">val lastx: &#39;a</div> <div class="fsdocs-tip" id="85">val lasty: &#39;b</div> <div class="fsdocs-tip" id="86">val changesx: (&#39;d * &#39;a) list (requires comparison)</div> <div class="fsdocs-tip" id="87">val changesy: (&#39;d * &#39;b) list (requires comparison)</div> <div class="fsdocs-tip" id="88">val d: &#39;d (requires comparison)</div> <div class="fsdocs-tip" id="89">val dx: &#39;d (requires comparison)</div> <div class="fsdocs-tip" id="90">val tailx: (&#39;d * &#39;a) list (requires comparison)</div> <div class="fsdocs-tip" id="91">val dy: &#39;d (requires comparison)</div> <div class="fsdocs-tip" id="92">val taily: (&#39;d * &#39;b) list (requires comparison)</div> <div class="fsdocs-tip" id="93">val apply: f: Series&lt;(&#39;a -&gt; &#39;b)&gt; -&gt; x: Series&lt;&#39;a&gt; -&gt; Series&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="94">val f: Series&lt;(&#39;a -&gt; &#39;b)&gt;</div> <div class="fsdocs-tip" id="95">val x: Series&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="96">val birthDate: DateTime</div> <div class="fsdocs-tip" id="97">DateTime.AddYears(value: int) : DateTime</div> <div class="fsdocs-tip" id="98">val potentialSells: availability: int -&gt; price: decimal -&gt; closed: bool -&gt; decimal</div> <div class="fsdocs-tip" id="99">val availability: int</div> <div class="fsdocs-tip" id="100">val price: decimal</div> <div class="fsdocs-tip" id="101">val closed: bool</div> <div class="fsdocs-tip" id="102">Multiple items<br />val decimal: value: &#39;T -&gt; decimal (requires member op_Explicit)<br /><br />--------------------<br />type decimal = Decimal<br /><br />--------------------<br />type decimal&lt;&#39;Measure&gt; = decimal</div> <div class="fsdocs-tip" id="103">val availability: Series&lt;int&gt;</div> <div class="fsdocs-tip" id="104">val price: Series&lt;decimal&gt;</div> <div class="fsdocs-tip" id="105">val closed: Series&lt;bool&gt;</div> <div class="fsdocs-tip" id="106">module Queries from 2020-10-03-applicatives-irl</div> <div class="fsdocs-tip" id="107">val queryService: properties: Set&lt;string&gt; -&gt; Map&lt;string,string&gt;</div> <div class="fsdocs-tip" id="108">val properties: Set&lt;string&gt;</div> <div class="fsdocs-tip" id="109">Multiple items<br />module Set from Microsoft.FSharp.Collections<br /><br />--------------------<br />type Set&lt;&#39;T (requires comparison)&gt; = interface IReadOnlyCollection&lt;&#39;T&gt; interface IStructuralEquatable interface IComparable interface IEnumerable interface IEnumerable&lt;&#39;T&gt; interface ICollection&lt;&#39;T&gt; new: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt; member Add: value: &#39;T -&gt; Set&lt;&#39;T&gt; member Contains: value: &#39;T -&gt; bool override Equals: objnull -&gt; bool ...<br /><br />--------------------<br />new: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt;</div> <div class="fsdocs-tip" id="110">Multiple items<br />module Map from Microsoft.FSharp.Collections<br /><br />--------------------<br />type Map&lt;&#39;Key,&#39;Value (requires comparison)&gt; = interface IReadOnlyDictionary&lt;&#39;Key,&#39;Value&gt; interface IReadOnlyCollection&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface ICollection&lt;KeyValuePair&lt;&#39;Key,&#39;Value&gt;&gt; interface IDictionary&lt;&#39;Key,&#39;Value&gt; new: elements: (&#39;Key * &#39;Value) seq -&gt; Map&lt;&#39;Key,&#39;Value&gt; member Add: key: &#39;Key * value: &#39;Value -&gt; Map&lt;&#39;Key,&#39;Value&gt; ...<br /><br />--------------------<br />new: elements: (&#39;Key * &#39;Value) seq -&gt; Map&lt;&#39;Key,&#39;Value&gt;</div> <div class="fsdocs-tip" id="111">val ofList: elements: (&#39;Key * &#39;T) list -&gt; Map&lt;&#39;Key,&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="112">val contains: element: &#39;T -&gt; set: Set&lt;&#39;T&gt; -&gt; bool (requires comparison)</div> <div class="fsdocs-tip" id="113">type Query&lt;&#39;t&gt; = { Properties: Set&lt;string&gt; Get: (Map&lt;string,string&gt; -&gt; &#39;t) }</div> <div class="fsdocs-tip" id="114">val prop: name: string -&gt; Query&lt;string&gt;</div> <div class="fsdocs-tip" id="115">val name: string</div> <div class="fsdocs-tip" id="116">val set: elements: &#39;T seq -&gt; Set&lt;&#39;T&gt; (requires comparison)</div> <div class="fsdocs-tip" id="117">val response: Map&lt;string,string&gt;</div> <div class="fsdocs-tip" id="118">val firstname: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="119">val lastname: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="120">val favoriteLanguage: Query&lt;string&gt;</div> <div class="fsdocs-tip" id="121">val callService: query: Query&lt;&#39;t&gt; -&gt; &#39;t</div> <div class="fsdocs-tip" id="122">val query: Query&lt;&#39;t&gt;</div> <div class="fsdocs-tip" id="123">Query.Properties: Set&lt;string&gt;</div> <div class="fsdocs-tip" id="124">Query.Get: Map&lt;string,string&gt; -&gt; &#39;t</div> <div class="fsdocs-tip" id="125">val map: f: (&#39;a -&gt; &#39;b) -&gt; q: Query&lt;&#39;a&gt; -&gt; Query&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="126">val q: Query&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="127">Query.Get: Map&lt;string,string&gt; -&gt; &#39;a</div> <div class="fsdocs-tip" id="128">val age: Query&lt;int&gt;</div> <div class="fsdocs-tip" id="129">val fullname: firstname: string -&gt; lastname: string -&gt; string</div> <div class="fsdocs-tip" id="130">val map2: f: (&#39;a -&gt; &#39;b -&gt; &#39;c) -&gt; x: Query&lt;&#39;a&gt; -&gt; y: Query&lt;&#39;b&gt; -&gt; Query&lt;&#39;c&gt;</div> <div class="fsdocs-tip" id="131">val x: Query&lt;&#39;a&gt;</div> <div class="fsdocs-tip" id="132">val y: Query&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="133">Query.Get: Map&lt;string,string&gt; -&gt; &#39;b</div> <div class="fsdocs-tip" id="134">val apply: f: Query&lt;(&#39;a -&gt; &#39;b)&gt; -&gt; x: Query&lt;&#39;a&gt; -&gt; Query&lt;&#39;b&gt;</div> <div class="fsdocs-tip" id="135">val f: Query&lt;(&#39;a -&gt; &#39;b)&gt;</div> <div class="fsdocs-tip" id="136">val userQuery: Query&lt;User&gt;</div>