Stack Builders logo
Arrow icon Insights

Minor improvement to yesod-forms: A Stack Builders open source update

At Stack Builders, we made a minor improvement to the yesod-forms library to make its monadic usage more concise.

Open source is the cornerstone of our consulting work, and we consider it one of our responsibilities to contribute back to the community that we depend on.

We are proud to share some of the open source contributions that we developed recently.

yesod-form

yesod is a well-known web framework in the Haskell community due its robustness and flexibility. One of the key components is called yesod-form, it's packaged with a lot of useful features to create HTML forms while helping keeping consistency during the serialization process. yesod-form let us use the same form for two different purposes:

  • Generate an HTML form representation.
  • Process the data from an upcoming request.

Additionally, yesod-form provides other key features that are quoted from the Yesod Web Framework Book:

  • Ensure data is valid.
  • Marshal string data in the form submission to Haskell datatypes.
  • Generate HTML code for displaying the form.
  • Generate Javascript to do clientside validation and provide more user-friendly widgets, such as date pickers.
  • Build up more complex forms by combining together simpler forms.
  • Automatically assign names to our fields that are guaranteed to be unique.

Yesod-form provides different flavors of web forms. For the sake of simplicity, we are going to mention just two of them - the "applicative" and "monadic" forms.

Applicative

These are the most commonly used. Applicative gives us some nice properties of letting error messages coalesce together and keep a very high-level, declarative approach.

Monadic

A more powerful alternative to applicative. While this allows you more flexibility, it does so at the cost of being more verbose. Useful if you want to create forms that don’t fit into the standard two-column look.

While Applicative forms syntax look very concise and readable, it's not possible to handle scenarios where a validation for a field depends upon other fields. This is where Monadic forms are an alternative. However, as their description states, there is a cost associated:

it does so at the cost of being more verbose.

In order to reduce some of the verbosity introduced by Monadic forms, Stack Builders pushed a PR containing a variant of a Monadic form. This new form introduces a WriterT to stack the FieldViews created as part of the form. Here is an example of a use case scenario built using MForm:

(field1F, field1V) <- mreq textField MsgField1 Nothing
(field2F, field2V) <- mreq (checkWith field1F textField) MsgField2 Nothing
(field3F, field3V) <- mreq (checkWith field1F textField) MsgField3 Nothing
return
  ( MyForm <$> field1F
           <*> field2F
           <*> field3F
  , [field1V, field2V, field3V]
  )

The previous example could be refactored as follows using WForm:

field1F <- wreq textField MsgField1 Nothing
field2F <- wreq (checkWith field1F textField) MsgField2 Nothing
field3F <- wreq (checkWith field1F textField) MsgField3 Nothing
return $
  MyForm <$> field1F
         <*> field2F
         <*> field3F

As readers can tell, the code is more compact - not exactly like the Applicative style, but at least there is no need to collect all generated fields manually.

For more details about the implementation check the PR.

blaze-markup

Blaze is another well-known library used by many different web frameworks, including Yesod, to create embedded HTML templates inside Haskell. blaze is packaged with the following features:

  • Pretty fast – have a look at our benchmarks.
  • Lightweight DSL syntax.
  • Embedded in Haskell.
  • Efficient Unicode support.
  • Supports HTML 4 Strict and HTML 5.
  • Tool to create code from an HTML file.

As GHC evolves, more types are been introduced to its core library called base. One of those is Natural which is a Type representing arbitrary-precision non-negative integers according to its description.

blaze-markup provides a mechanism to transform Haskell data types into markup values, using a type class called ToMarkup. blaze-markup defined some ToMarkup instances for most common Haskell base types. Here at Stack Builders we submitted a PR introducing an instance of ToMarkup for Natural.

For more details about the implementation see the PR with the code that we added to blaze-markup.

Published on: Jan. 12, 2018
Last updated: Sep. 30, 2022

Written by:

DevOps
Sebastián Estrella

Subscribe to our blog

Join our community and get the latest articles, tips, and insights delivered straight to your inbox. Don’t miss it – subscribe now and be part of the conversation!
We care about your data. Check out our Privacy Policy.