<h2 id="intro">Intro</h2>
<p>I have been doing series about web programming in Haskell and realized that I might have skipped over some very basic details. Better later than never, I’ll go over some of them briefly (data types and database actions). Hopefully things will make more sense after this (like with my friend, whose last programming course was programming 101 and they said afterwards that now all that 3d and game programming is suddenly making sense).</p>
<h2 id="data-types">Data types</h2>
<p>Data here has nothing to do with databases (yet). This is how you can declare your own data types in Haskell. They’re declared with keyword <code>data</code> followed with type name, equals sign and one or more value constructors. Type name and value constructors have to start with uppercase letter.</p>
<p>Simplest type is following:</p>
<pre><code>data Simple = One</code></pre>
<p>This declares a type called <code>Simple</code> that has single possible value: <code>One</code>.</p>
<p>More interesting type is shown below. <code>Colour</code> has three possible values: <code>Red</code>, <code>Green</code> and <code>Blue</code>.</p>
<pre><code>data Colour =
    Red
    | Green
    | Blue</code></pre>
<p>It’s possible to have parameters in value constructor. Following is <code>Payment</code> type that could be used to indicate how payment was done. In case of <code>Cash</code> amount is stored. In case of <code>IOU</code> free text is recorded.</p>
<pre><code>data Payment =
    Cash Double
    | IOU Text</code></pre>
<p>Fictional usage of the <code>Payment</code> is shown below. Function <code>paymentExplanation</code> takes a <code>Payment</code> as parameter and returns <code>Text</code> describing the payment. In case of cash payment, brief explanation of how much was paid is returned. In case of IOU slip the function returns explanation stored in <code>IOU</code> value.</p>
<p><code>paymentExplanation :: Payment -&gt; Text</code> part is type declaration. It states that <code>paymentExplanation</code> takes argument of type <code>Payment</code> and returns result as <code>Text</code>.</p>
<pre><code>paymentExplanation :: Payment -&gt; Text
paymentExplanation payment =
    case payment of
        Cash amount -&gt;
            &quot;Cash payment of &quot; &lt;&gt; (show amount) &lt;&gt; &quot; euros&quot;
        IOU explanation -&gt;
            explanation</code></pre>
<p>Parameters don’t have to be hard coded in the type definition. Parametrized types allows creating more general code. <code>Maybe</code> is very useful data type that is often used for data that might or might not be present. It can have two values: <code>Nothing</code> indicating that there isn’t value and <code>Just a</code> indicating that value is present.</p>
<pre><code>data Maybe a =
    Nothing
    | Just a</code></pre>
<p><code>a</code> is type parameter that is filled in when declaring type. Below is a function that takes <code>Maybe Payment</code> as a parameter and if value of <code>payment</code> parameter is <code>Just</code> returns explanation of it (reusing the function we declared earlier). In case of <code>Nothing</code> <code>&quot;No payment to handle&quot;</code> is returned.</p>
<pre><code>invoice :: Maybe Payment -&gt; Text
invoice payment =
    case payment of
        Just x -&gt;
            paymentExplanation x
        Nothing -&gt;
            &quot;No payment to handle&quot;</code></pre>
<p>Alternatively one can omit <code>case</code> expression as shown below and write different value constructors directly as parameters. In both cases, compiler will check that programmer has covered all cases and emit a warning if that’s not the case.</p>
<pre><code>invoice :: Maybe Payment -&gt; Text
invoice (Just payment) =
    paymentExplanation payment

invoice Nothing =
    &quot;No payment to handle&quot;</code></pre>
<p>Having several parameters gets soon unwieldy, so lets introduce records. With them, fields have names that can be used when referring to them (either when creating or when accessing the data). Below is <code>Person</code> record with two fields. <code>personName</code> is of type <code>Text</code> and <code>personAge</code> of type <code>Age</code> (that we’ll define in the next step).</p>
<pre><code>data Person = Person
    { personName :: Text
    , personAge :: Age
    }</code></pre>
<p>To access data in a record, just use field as a function (there’s a bug, I’m turning 40, this month (today even, to be specific, didn’t realize this until I was about to upload the episode), but forgot such a minor detail when recording the episode):</p>
<pre><code>me = Person { personName = &quot;Tuukka&quot;, personAge = 37 }
myAge = personAge me
myName = personName me</code></pre>
<p>New type is special type of record that can has only one field. It is often used to make sure one doesn’t mix similar data types (shoe size and age can both be Ints and thus mixed if programmer isn’t being careful). Compiler will optimize new types away during compilation, after checking that they’re being used correctly. This offers a tiny performance boost and makes sure one doesn’t accidentally mix different things that happen to look similar.</p>
<pre><code>newtype Age = { getAge :: Int }</code></pre>
<p>One can instruct compiler to derive some common functions for the data types. There are quite many of these, but the most common ones I’m using are <code>Show</code> (for turning data into text), <code>Read</code> (turning text into data) and <code>Eq</code> (comparing equality).</p>
<pre><code>data Payment =
    Cash Double
    | IOU Text
    deriving (Show, Read, Eq)</code></pre>
<h2 id="database">Database</h2>
<p>In case of Yesod and Persistent, database structure is defined in models file that usually located in config directory. It is read during compile time and used to generate data types that match the database. When the program starts up, it can check structure of the database and update it to match the models file, if migrations are turned on. While this is handy for development, I wouldn’t dare to use it for production data.</p>
<p>Following definitions are lifted from the models file of the game I’m working.</p>
<pre><code>StarSystem
    name Text
    coordX Int
    coordY Int
    deriving Show Read Eq</code></pre>
<p>This defines a table <code>star_system</code> with columns <code>id</code>, <code>name</code>, <code>coord_x</code>, <code>coord_y</code>. All columns have <code>NOT NULL</code> constraint on them. It also defines record <code>StarSystem</code> with fields <code>starSystemName</code>, <code>starSystemCoordX</code> and <code>starSystemCoordY</code>.</p>
<pre><code>Star
    name Text
    starSystemId StarSystemId
    spectralType SpectralType
    luminosityClass LuminosityClass
    deriving Show Read Eq</code></pre>
<p>This works in the same way and defines table <code>star</code> and record <code>Star</code>. New here is column <code>star_system_id</code> that has foreign key constraint linking it to <code>star_system</code> table. <code>Star</code> record has field <code>starStarSystemId</code> (silly name, I know, but that’s how the generated names go), which has type <code>Key StarSystem</code>.</p>
<p><code>spectral_type</code> and <code>luminosity_class</code> columns in the database are textual (I think <code>VARCHAR</code>), but in the code they’re represented with <code>SpectralType</code> and <code>LuminosityClass</code> data types. In order this to work, we have to define them as normal data types and use <code>derivePersistField</code> that generates extra code needed to store them as text in database:</p>
<pre><code>data SpectralType = O | B | A | F | G | K | M | L | T
    deriving (Show, Read, Eq)
derivePersistField &quot;SpectralType&quot;

data LuminosityClass = Iap | Ia | Iab | Ib | II | III | IV | V | VI | VII
    deriving (Show, Read, Eq)
derivePersistField &quot;LuminosityClass&quot;</code></pre>
<p>Final piece in the example is <code>Planet</code>:</p>
<pre><code>Planet
    name Text
    position Int
    starSystemId StarSystemId
    ownerId FactionId Maybe
    gravity Double
    SystemPosition starSystemId position
    deriving Show Read Eq</code></pre>
<p>This introduces two new things: <code>ownerId FactionId Maybe</code> removes <code>NOT NULL</code> constraint for this column in the database, allowing us to omit storing a value there. It also changes type of <code>planetOwnerId</code> into <code>Maybe (Key Faction)</code>. Thus, planet might or might not have an owner, but if it has, database ensures that the link between <code>planet</code> and <code>faction</code> (not shown here) is always valid.</p>
<p>Second new thing is <code>SystemPosition starSystemId position</code> that creates unique index on columns <code>star_system_id</code> and <code>position</code>. Now only one planet can exists on any given position in a star system.</p>
<p>Database isn’t any good, if we can’t insert any data into it. We can do that with a function shown below, that create a solar system with a single planet:</p>
<pre><code>createSolarSystem = do
    systemId &lt;- insert $ StarSystem &quot;Solar system&quot; 0 0
    starId &lt;- insert $ Star &quot;Sol&quot; systemId G V
    planetId &lt;- insert $ Planet &quot;Terra&quot; 3 systemId Nothing 1.0
    return (systemId, starId, planetId)</code></pre>
<p>To use the function, we have to use <code>runDB</code> function that handles the database transaction:</p>
<pre><code>res &lt;- runDB createSolarSystem</code></pre>
<p>There are various ways of loading data from database. For loading a list of them, <code>selectList</code> is used. Here we’re loading all planets that have gravity exactly 1.0 and ordering results by the primary key in ascending order:</p>
<pre><code>planets &lt;- runDB $ selectList [ PlanetGravity ==. 1.0 ] [ Asc PlanetId ]</code></pre>
<p>Loading by primary key is done with <code>get</code>. It returns <code>Maybe</code>, because data might or might be present that match the primary key. Programmer then has to account both cases when handling the result:</p>
<pre><code>planet &lt;- runDB $ get planetId</code></pre>
<p>Updating a specific row is done with <code>update</code> function (<code>updateWhere</code> is for multiple rows):</p>
<pre><code>_ &lt;- runDB $ update planetId [ PlanetName =. &quot;Earth&quot; ]</code></pre>
<p>Finally, sometimes it’s nice to be able to delete the data:</p>
<pre><code>_ &lt;- runDB $ delete planetId
_ &lt;- runDB $ deleteWhere [ PlanetGravity &gt;. 2 ]</code></pre>
<p>While persistent is relatively easy to use after you get used to it, it lacks ability to do joins. In such cases one can use library called Esqueleto, that is more powerful and has somewhat more complex API.</p>
<h2 id="extra">Extra</h2>
<p>Because functions are values in Haskell, nothing prevents storing them in data types:</p>
<pre><code>data Handler =
    Simple (Int -&gt; Boolean)
    | Complex (Int -&gt; Int -&gt; Int)</code></pre>
<p><code>Handler</code> type has two possible values: <code>Simple</code> has a function that turns <code>Int</code> into <code>Boolean</code> (for example <code>odd</code> used to check if given number is odd) and <code>Complex</code> that takes two values of type <code>Int</code> and returns <code>Int</code> (basic arithmetic for example, adding and subtracting).</p>
<p>Hopefully this helps you to follow along as I work on the game.</p>
<p>Easiest way to catch me nowadays is either via email or on fediverse where I’m Tuula@mastodon.social</p>
