Bindings, Platforms, and Innovation
This presentation focuses on the Internet and separating myth from fact, history from the future, and the mundane from the imaginative. Bob Frankston presents a vision of what could and should be.
Tracking change and innovation in the enterprise software development community

Posted by Robert Pickering on Jan 03, 2008 10:00 AM
This article builds on my previous article for InfoQ, "Beyond Foundations of F# - Active Patterns", introducing another new language feature - workflows. Chapter 11 of the introductory book to F#, "Foundations of F#" (apress, May 2007), covers language ordinate programming, a technique where program as are written using domain specific language (DSLs). These DSLs may be implemented separately using text or xml to represent the language. Often the DSL may be entirely embedded within a general purpose programming language using the data structures and other features of the language to represent the DSL. Workflows are a feature designed to build on the already strong language ordinate programming features of F#. Workflows allow you to capture a small section of code and examine its contents, giving library implementers a chance to use this as the building block for their DSLs - a technique similar to expression trees in C# 3.0. In this article will take a look under the hood and dig into how workflows work in F#.F# is a statically typed functional programming language that targets the .NET framework. It shares a common core language with OCaml, another popular functional programming language, and draws ideas from many other programming languages, including Haskell, Erlang, and C#. In a nutshell this means that F# is a programming language that has a nice succinct syntax that feels a bit like scripting as we are able to execute the code interactively but F# has all the type safety and performance of a compiled language. This article is not indented to be an introduction to F# as there are already many resources on the web intended to make learning F# easy. See the side bar "F# Resources" in my previous article on F#.

This is quite a bit of code. Let's break it down piece by piece and look at how each of these pieces works with our original script. The first type definition defines the type for our script. In this case a script is a function that will yield a value. The script "num" we defined earlier has the type Script
Effective Management of Static Analysis Vulnerabilities and Defects
Agile Development: A Manager's Roadmap for Success
The Agile Business Analyst: Skills and Techniques needed for Agile
NEW: ANTS Memory Profiler 5 now out!
Give-away eBook – Confessions of an IT Manager
The next major part of the library components is the ScriptBuilder class. This defines the methods that will be used handle the various expressions that make up our script. The various parts of the expressions will be handed to the methods as values. Here the "Return" and "Let" methods handle the let and return bindings in the script. The more interesting of these is the let binding. In the let binding the "printfn" function is used to print out the value of the parameter - meaning that as the script executes the values within the let bindings are printed to the console. The idea being that this is a very useful aid for debugging. Finally, the last item shows instancing of the ScriptBuilder class. It is in this instance "script" is used within the "num" workflow. So when "num" script is executed:
runScript num
the following is output to the console:
2
21
val it : int = 42
The first two values are the values of the let bindings being printed out and the final values F# interactive automatically printed out the function result along with its type.
In workflows it is not only possible to handle normal F# expressions such as let, as shown earlier, but also new expressions such as "let!" (pronounced let bang) and "yield" along with several others. This provides the real power of workflows, allowing library implementers to take these keywords and give new meanings to them.
Now we will extend the example to include the "let!" binding expressions too. Supposing that we do not want every let binding to be printed to the console, we may just want key bindings to be printed out, implementing the "let!" provides a convenient way to allow programmers to choose which bindings to print. This is implemented by the addition of the following method to the "ScriptBuilder" class, to handle the let! binding:
We also need to make a small alteration to the "Let", to remove printing to the console:
So now when we define and run a script we can use the let! binding to print certain let bindings to the console:
Now only 21 will be printed to the console:
21
val it : int = 42
How does the F# compiler do the translation between the workflow and the final expression executed? This process is called "de-sugaring" and will dig into how it works in the next section.
The expressions in a workflow are transformed into a data structure that uses "continuation passing style", this process is known as de-sugaring, as the workflow is really just "syntactic sugar".
A good place start understanding this is by coming back to our simple example:
is translated into:
The advantage of not having to type out this structure by hand is obvious. The "sugared" version is shorter and much easier to understand and typing out the non-sugared version would be both difficult and error prone. The advantages of having an expression in this form, rather than just an ordinary expression, are slightly more subtle. The important point to notice is the Bind and Let methods being called. These methods are called with the parameter to the let binding as the first parameter and a continuation - a function waiting for the value - as the second. It is this that allows us to do the trick of printing out the parameter "p" and then passing it to the "rest" function to continue the computation, seen here in the definition of the "Bind" method:
printfn "%A" p
rest p
This is the very heart of workflows in F#. The continuation style passing allows developers to insert extra actions when a value is being bound. In our example these actions are somewhat trivial, but these actions can be as involved as waiting for an asynchronous computation to complete and then continuing with the action - as we will see in the next article in this series which looks at asynchronous workflows.
So far our little debug script may have looked like quite an unimpressive use of workflows. Let's now dig into a more realistic example using sequence workflows. Sequence workflows are a type of workflow that is available as part of the F# base class libraries. Sequence expressions are useful to create collections. For example, the following sequence expression creates a list of the first three square numbers and there square roots:
One of the most useful features of the sequence expressions are their use of the yield keyword, which is used to return a value that is part of the collection then carry on the computation. For example, the following code reads a text file yielding each line to produce a sequence of the lines of the text file:
It is also possible to use the yield!, (pronounced yield bang), keyword in sequence expressions. This allows you to add a sequence of elements to the collection and so it is often used in recursive sequence expressions. The following shows how to use a recursive sequence expression to flatten a tree of WPF controls into a sequence. This is very useful if you want to apply some operation to every item in the control tree:
We see that on the first line of the sequence expression we yield the first item we are given into the collection. Then, in the second half of the sequence expression we use a for loop to enumerate each of the control's child and recursively call "treetoList" on them. The sequence that this returns is then placed into the collection using the yield! keyword, thus flattening the tree to a list.
To see this sequence expression in action you need to use the following code to create a WPF window:
Workflows are covered in detail in chapter 9 of "Expert F#" by Don Syme, Adam Granicz, and Antonio Cisternino.
Workflows are a powerful technique that allows library designers to create libraries that have a huge amount of flexibility. Not all F# programmers will use workflows to create their own DSLs, but it is highly likely that F# programmer will use libraries written using workflows at some point, the sequence workflow are too useful to miss out on. In the next article in this series well take a look at asynchronous workflows, another innovative use of workflows that simplifies using the .NET asynchronous programming model.
This presentation focuses on the Internet and separating myth from fact, history from the future, and the mundane from the imaginative. Bob Frankston presents a vision of what could and should be.
This article explores the use of JBoss and jBPM to implement design solutions that effectively address the issue of orchestrating long running activities.
This presentation covers the use of graph databases as an optimal solution for data that is difficult to fit in static tables, rapidly evolving data or data that has a lot of optional attributes.
This session introduces Real Options and shows how it can help in running your project. Real Options is a decision-making process that can be used to manage risk.
This article discusses the use of bindings on services and references (including the instance of non-configured bindings) as the means to implement SCA communications in a Web and SOA environment.
After a short introduction to DSLs, Scott Davis plays with the keyboard showing how to approach the creation of a DSL by typing working snippets of Groovy code that get executed.
IBM Rational and InfoQ present, Scaling Agile with C/ALM, an eBook showing organizations how to become “finely tuned software delivery machines” by enabling team integration and scaling.
Amanda Laucher presents a real life enterprise application written in F#. She shows actual code snippets, explaining design decisions and suggesting how to use some of the F# constructs.
No comments
Watch Thread Reply