TP

Beyond the Monad fashion (II.): Creating web forms with LINQ

The LINQ query syntax can be used for various things. Aside from writing queries, you can also use it to encode any monads. This has become a fashionable topic, so you can learn more about it at many .NET conferences (for example GOTO 2011). There are also many blog posts on this topic and I explained it in details in Chapter 12 of my book [1], which is available as a free sample chapter (PDF).

However, you can also use LINQ syntax for writing different types of computations. In a previous blog post, I introduced idioms (also called applicative functors) and I demonstrated how to use the join syntax in LINQ to write computations based on idioms. We looked at a slightly boring, but simple example - zipping of lists - and we also implemented matrix transposition.

In this blog post, we look at a more exciting example. I explain formlets, which is an idiom for building web forms. Formlets give us an elegant functional way to create reusable components that encapsulate both visual aspect (HTML) and behavior (processing of requests). You can think of them as functional ASP.NET controls. Formlets come from the Links project [2] and they are now used in commercial products like WebSharper [3]. In this article, you'll see that we can (mis)use LINQ to get a nicer syntax for writing code using formlets. My C# implementation of formlets is based on a nice F# formlets by Mauricio Scheffer [4].

The idea of formlets

The key of formlets is simple. A formlet is some object of type Formlet<T> that represents a part of a HTML form that is used for entering values of type T. For example, a simple HTML <input /> will be represented as Formlet<string>. A more sophisticated component for selecting a date will be represented as Formlet<DateTime>.

Now, what does it mean to represent a part of an HTML form? As already mentioned, there are two aspects of a HTML form that we'd like to encapsulate in a formlet:

Abstract formlet type

Let's look how to model the two aspects using a simple F# type and we'll look at actual C# implementation later. To get some intuition about formlets, you can take a look at the diagram on the right. The two aspects of formlets can be modeled as two separate functions. For simplicity, we group them in a record:

type Formlet<'T> = 
  { // Takes counter and generates XML together with new counter
    Render   : int -> XElement * int
    // Takes counter and form values and generates result with new counter
    Evaluate : int * NameValueCollection -> 'T * int }

The first function is used to render the formlet. When the page is loaded for the first time, we don't have any form values, so the rendering phase shouldn't rely on any inputs. The function just needs to produce some HTML output (stored as XElement). To be able to compose formlets, we pass around an int value that is used to generate unique id attributes.

The second function represents is used to process the next request from the client. When the user submits a form, we get NameValueCollection storing the form values. The Evaluate function turns the collection into a value of type 'T (e.g. string or DateTime). We need to know the generated id to pick values from the collection, so we pass around an int counter in the same way as during rendering.

Why are formlets interesting?

The key thing that makes formlets interesting is that they are not monads. The operation that determines this is composition. A typical scenario is that we have some basic formlets (e.g. Formlet.Input(label) that generates <input> with a specified label) and we want to compose them. When composing formlets, the second formlet must not depend on the value produced by the first formlet. Using nested from clauses in LINQ (or using monads), we could write:

Formlet<DateTime> dateFormlet = 
  from day in Formlet.Input("Enter day:")
  from month in Formlet.Input("Enter month (selected day is {0}):", day)
  select new DateTime(day, month, 2011); 

The tricky thing in the snippet above is that we're using the variable day (representing value obtained from the first input) when creating the second input. If you think about it, this cannot possibly work, because there is no way the Render method could work. When rendering the form, we don't have form values, so we cannot assign any value to the day variable.

This demonstrates an important property of monads - when composing two monads, we can use the value generated by the first one when creating the second one. This is also how from clause behaves in LINQ and why it doesn't work in our example.

On the other hand, when composing formlets we can only use the values produced by formlets after we specify all the formlets that we want to compose. This code will not be executed during rendering (rendering will just render all formlets), but it will be used when processing the second request. Interestingly, it is still possible to write formlets using LINQ...

Creating booking form with formlets

In this section, we look at an example that uses formlets to create a simple booking form consisting of input for entering name and two controls for entering date (using drop-down boxes for selecting date, month and a year). We start by looking how to write this using LINQ and then we'll gradually explain how the solution works under the cover.

Writing formlets using LINQ

As I explained in a previous blog post, we can encode idioms (such as formlets) using the LINQ syntax. We've seen that we cannot use from clause (as when encoding monads), but we can do that using the join clause (and providing some dummy key selectors such as on 1 equals 1).

The following example uses this trick to create a formlet. We use a simple library with formlets for basic HTML elements. The Formlet.DropDownRange method creates formlet that represents drop-down containing numbers specified by the range (HTML <select>) and Formlet.DropDown fills the drop-down using a specified collection of key-value pairs; Formlet.Tag creates a simple HTML tag and Formlet.Input creates a HTML text-box.

The following LINQ snippet creates the form shown on the screenshot at the beginning of the article:

Formlet<DateTime> dateSelector =
  from day in Formlet.DropDownRange(1, 31)
  join month in Formlet.DropDown(monthNames) on 1 equals 1
  let monthNum = Int32.Parse(month)
  join year in Formlet.DropDownRange(1960, 50) on 1 equals 1
  select new DateTime(year, monthNum, day);

Formlet<Booking> formlet =
  from name in Formlet.Input()
  join o1 in Formlet.Tag("br") on 1 equals 1
  join departureDate in dateSelector on 1 equals 1
  join o2 in Formlet.Tag("br") on 1 equals 1
  join returnDate in dateSelector on 1 equals 1
  select new Booking { Name = name, Departure = departureDate, Return = returnDate };

The first expression creates a formlet that can be used for entering dates. It renders three drop-down controls for entering day, month and a year. When writing the first one, we start the query with the from clause. To add the other two, we use join. We also use let inside the query to parse the string obtained from a drop-down. This is fine, but the LINQ syntax doesn't allow us to use the monthNum variable inside the next join. The let declaration is only useful to keep logically related things nearby, but it is always possible to move all calculations to the last select clause.

The second expression creates a formlet for entering the whole booking. It starts with an usual input element and then it re-uses the formlet for generating date selector two times. The types of departureDate and returnDate are both DateTime, so this gives us a nice way of composing forms in a statically type-safe way. We also use a couple of Tag formlets to add line breaks (we still have to assign the result to some variable, but we can then ignore them).

I hope you'll agree that the syntax is quite neat. You can get a complete sample (integrated in an ASP.NET MVC application) at the end of the article. Before writing a few things about the ASP.NET MVC integration, let's look how the same formlet could be created using idiom primitives.

Writing formlets explicitly

As discussed in the previous blog post, every idiom needs to provide three primitive operations: Return, Merge and Select. We can rewrite the previous example using the two latter ones. The Merge operation is used to combine two idioms (e.g. formlets) into a single one that produces tuple containing values produced by both. Select gives us a way to apply some calculation to transform the carried value:

Formlet<DateTime> dateSelector =
  Formlet.DropDownRange(1, 31).Merge
    (Formlet.DropDown(monthNames).Select(Int32.Parse)).Merge
    (Formlet.DropDownRange(1960, 50)).Select(tup =>
  new DateTime(tup.Item1.Item1, tup.Item1.Item2, tup.Item2));

The snippet composes three formlets using Merge. The first and the third formlets are simply generated using DropDownRange. The second one generates a drop-down for selecting months and we transform it using Select to get a formlet that produces the number of month as an int (corresponding to let in earlier LINQ query). The type of the composed formlet is Formlet<Tuple<int, Tuple<int, int>> and we use Select to turn the (ugly) nested tuple into a (nice) DateTime value.

ASP.NET MVC Integration

To make the article complete, I'll just briefly demonstrates how can formlets be integrated into an ASP.NET MVC application. After we declare a formlet (either in a separate file or as part of a controller class), we can use it in two view pages. In a first page, we want to render the formlet. To do this, we can simply assign the formlet to the Model property of the page. The ASP.NET markup for rendering the formlet looks like this:

<%@@ Page Language="C#" Inherits="ViewPage<Formlet<Booking>>" %>

<!-- Standard HTML markup -->  
<% using (Html.BeginForm("Booking", "Home")) { %>
  <%= Model.Render() %>
  <input type="submit" value="Submit" />
<% } %>

In the @@ Page directive, we specify that the model of the page is a formlet, so that we can access it via the Model property in a typed way. The page can contain any standard HTML markup. To include our form in the page, we create an HTML form (in a standard way) and then call Model.Render() to render the formlet. The method returns XDocument which will be printed to the output. (Earlier, we said that the method also takes an integer, but we can create an overload that calls the full version with 0 as an argument).

When the form is submitted to a separate page (as specified by the HTML form), we want to obtain the Booking object from the formlet. The values of generated HTML elements are stored in Request.Form (which is a NameValueCollection). We can call Evaluate method of the formlet as follows:

Booking res = formlet.Evaluate(Request.Form);
ViewData.Model = res;

In the C# code of the page, we can use the Evaluate method. Just like in the previous snippet, we're using a slightly simplified version of the method. This overload takes just a NameValueCollection with the form values and gives us a result of type Booking (because our formlet has a type Formlet<Booking>).

The purpose of this short section was just to demonstrate that you can use formlets like this as part of a real application. As already mentioned, you can find source code for this sample at the end of the article. Now that you've seen an example of working with formlets, let's look how C# formlets are implemented...

Looking under the cover

As already mentioned, the implementation I'm using is based on an F# formlets by Mauricio Scheffer [4]. His implementation uses slightly different definition of idioms, but the idea is the same. In the next section, we start by looking at the actual definition of Formlet<T> type.

Defining the Formlet type

When introducing formlets earlier, I wrote that formlets can be viewed as two functions (one for rendering and one for evaluation). We needed to pass around int value as a counter in both of the functions. The actual implementation uses a slightly different representation. Here, a formlet contains just a single function that takes int and produces FormletResult<T>. The result consists of a rendered XML and a function that can be used (when evaluating) to turn form inputs into a value (I'm using Environment as an alias for NameValueCollection):

class FormletResult<T> {
  // Rendered form stored as a list of XML elements
  public IEnumerable<XNode> Elements { get; set; }
  // Function (created by formlet) for processing form inputs
  public Func<Environment, T> Collector { get; set; }
  // Counter value after processing the formlet
  public int Counter { get; set; }
}

class Formlet<T> {
  // Function that runs the formlet when given an 'int' value
  public Func<int, FormletResult<T>> Func { get; set; }
  
  // Phase 1: Use formlet to create HTML of a form  
  public XDocument Render() {
    return new XDocument(new XElement("div", Func(0).Elements));
  }
  // Phase 2: Use formlet to process form inputs
  public T Evaluate(Environment env) {
    return Func(0).Collector(env);
  }
}

The type declarations are fairly simple. The FormletResult<T> type simply stores rendered elements, function for evaluation and a new counter. For simplicity, I'm using mutable properties, but we'll use the type in an immutable fashion (we will use setter only when creating the object).

The Formlet<T> type is also quite simple. It contains a function that can be called with initial counter as an argument and produces FormletResult<T>. The function is called when we want to render the formlet as well as when we want to process form inputs. In the first case (the Render method), we simply call the function and wrap all generated XML elements inside a single <div> element. In the second case (Evaluate), we first run the function and then use the constructed function (named Collector) to actually process the inputs. Note again that we don't need the form inputs to render the formlet!

In the implementation, we also declare a static method Formlet.Create (in a static non-generic class), so that we can create formlets and benefit from the C# type inference for generic method calls. The next section gives some examples...

Building primitive formlets

When creating complex formlets such as the date selection or the booking form above, we can use LINQ query syntax and compose them from simpler formlets. However, elementary formlets such as Formlet.Input() need to be created explicitly. This is also a good way to understand how formlets work:

public static Formlet<string> Input() {
  return Formlet.Create(counter => new FormletResult<string> {
    Elements = new List<XElement> {
      new XElement("input", new XAttribute("name", "frmel" + counter))
    },
    Counter = counter + 1
    Collector = env => env["frmel" + counter],
  });
}

To create a formlet for input, we need to write a function that constructs FormletResult<string> when given an integer (counter). In this simple example, we set Elements to a list containing a single <input> element. The id attribute of the element is set to some generated name that includes the current value of counter. The Counter property is set to the successor of counter, because we used a single ID. This way, we can compose two Input formlets and they will use different id.

Finally, we also need to construct the Collector function. This is quite simple. When given an environment (a NameValueCollection value), the function performs a lookup using the same id that it used during rendering. The value from the collection is a string, so it can be returned as a result.

Implementing idiom operations

As mentioned earlier, formlets are idioms, which is a type of computation that I introduced in the previous blog post. Every idiom needs to provide three operations: Merge, Select and Return (using these operations, we can also implement Join extension method that is used by LINQ when translating the join clause). The types of the three methods that we need to implement for formlets are explained in the previous article. Once we have the types, writing the actual implementation is quite easy (I omitted the Return operation, because it isn't particularly useful for formlets):

// Create formlet that composes two formlets. The formlets are rendered
// in in sequence and their values are merged into a tuple.
public static Formlet<Tuple<T1, T2>> Merge<T1, T2>
    (this Formlet<T1> first, Formlet<T2> second) {
  return Formlet.Create(i => {
    var v1 = first.Func(i);
    var v2 = second.Func(v1.Counter);
    return new FormletResult<Tuple<T1, T2>> {
      Elements = Enumerable.Concat(v1.Elements, v2.Elements),
      Collector = env => 
        Tuple.Create(v1.Collector(env), v2.Collector(env)),
      Counter = v2.Counter
    };
  });
}

// Create formlet that transforms value created by the original formlet;
// rendering just returns elements of the original formlet.
public static Formlet<R> Select<T, R>
    (this Formlet<T> source, Func<T, R> func) {
  return Formlet.Create(i => {
    var value = source.Func(i);
    return new FormletResult<R> {
      Elements = value.Elements,
      Collector = env => func(value.Collector(env)),
      Counter = value.Counter
    };
  });
}

When combining two formlets using Merge, we run the functions that define them in sequence. We pass initial counter to the first formlet and then pass the returned (incremented) counter to the second formlet. To build the result, we simply concatenate all generated XML elements. The Collector function runs Collector function of both original formlets and returns a tuple carrying both values together.

The Select operation builds formlet that behaves similarly to the original formlet. The only difference is that the Collector function transforms the value using a provided function. This is how we turn the tuple values created by Merge into the final result of a formlet (such as DateTime).

Now that we have the idiom operations, it is very easy to support the LINQ syntax using the join clause. We just need to implement the Join method in terms of Merge and Select. This implementation is exactly the same for all idioms, so you can find it in the previous article.

Summary

In this article we looked how to use the concept of formlets in C# using the LINQ query syntax. Formlets is a nice functional abstraction for HTML forms. They encapsulate two aspects of HTML forms - request processing and form rendering - in a single composable type.

Formlets are interesting because they are idioms. This is an abstract type of computations (just like pupular monads). Interestingly, formlets cannot be treated as monads, because we cannot use value produced by formlet as argument to a second formlet in composition. This may be a bit confusing, but when you'll try to implement SelectMany for formlets, you'll see the problem.

The fact that the structure of formlet cannot depend on the values is an essential aspect of idioms. However, even though formlets are not monads, we can use a nice LINQ query syntax to write them. In a sense this controverts the general sense that LINQ is a monad. The trick is that we build our syntax on the join clause which is handled using different rules than nested from clauses (usually used for monads).

References & Downloads

Published: Monday, 14 March 2011, 5:14 PM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: c#, research