Most Haskell programmers have a PhD and they don’t mind overly concise notation, but there are times when the combination of Haskell features (monads, GADTs, SYB, forall, exists, rank-2, …) starts to hurt. Then it is time to switch to a more obvious notation that can be understood by human beings and machines equally well. Now, a Haskell programmer will not be willing to consider plain XML, as this would be too untyped. Hence, XML Schema is the obvious choice. Don’t expect to be able to express each and every Haskell datatype as an XSD type (neither vice versa). However, the following mapping gets you pretty far:

 

  • A named algebraic datatype becomes the head of a substitution group.
  • You also define a base complex type; perhaps even use the same name.
  • Each constructor declaration becomes a substitution-group member.
  • Different degrees of conciseness are achievable:
    • Use an anonymous complex type for each substitution-group member.
    • Use a named complex type instead.

W.L.O.G., we go for the concise mapping below.

 

Let’s consider an algebraic datatype for expression forms.

First-year students are normally overwhelmed by the following line of Haskell code.

 

data Exp = Zero | Succ Exp | Add Exp Exp

 

Using the above mapping, we can help these students by expressing the intent in a more telling manner:

 

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="exp" type="exp" abstract="true"/>

  <xs:complexType name="exp"/>

  <xs:element name="zero" substitutionGroup="exp">

    <xs:complexType>

      <xs:complexContent>

        <xs:extension base="exp"/>

      </xs:complexContent>

    </xs:complexType>

  </xs:element>

  <xs:element name="succ" substitutionGroup="exp">

    <xs:complexType>

      <xs:complexContent>

        <xs:extension base="exp">

          <xs:sequence>

            <xs:element ref="exp"/>

          </xs:sequence>

        </xs:extension>

      </xs:complexContent>

    </xs:complexType>

  </xs:element>

  <xs:element name="add" substitutionGroup="exp">

    <xs:complexType>

      <xs:complexContent>

        <xs:extension base="exp">

          <xs:sequence>

            <xs:element ref="exp"/>

            <xs:element ref="exp"/>

          </xs:sequence>

        </xs:extension>

      </xs:complexContent>

    </xs:complexType>

  </xs:element>

</xs:schema>

 

This idea actually scales pretty well.