- May 9, 2017: changes

This post is a tutorial on applicative functors (applicatives) and alternatives - what they are, how they’re used, and how to build an intuition for them.

It’s going to be extremely practical. It’s going to be all Haskell. We’ll build stuff along the way so that it makes more sense.

The following imports are assumed to be in scope for this post:

```
import Control.Applicative
import Data.Monoid
```

All code used in this post is available here.

Let’s start with some informal definitions.

An applicative is an abstraction that lets us express function composition in a context. Applicative composition only succeeds if each independent component in the computation succeeds. Rules for what success looks like vary from context to context. Its interface looks like this.

```
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
```

Notably, all applicative functors must also be functors. We won’t cover functors here, but it suffices to say that they’re an abstraction for applying context-free functions to context-embedded values.

`pure`

is sometimes called `lift`

because it lifts a pure value of type `a`

into the context `f`

. `<*>`

is our applicative composition operator. It allows us to chain together contextual computations.

An alternative is an abstraction that builds on applicatives. Like it sounds, it allows to express the idea of trying something else in case something fails. Composition of alternatives take the first success. Its interface looks like this:

```
class Applicative f => Alternative (f :: * -> *) where
empty :: f a
(<|>) :: f a -> f a -> f a
```

`empty`

is our failure value, to represent a failure of all alternatives. `<|>`

is our composition operator, for chaining together alternatives.

With those definitions out of the way -

Let’s build our first applicative! To do so, we’ll look at the `Option`

type.

An `Option`

or `Maybe`

type allows us to express the idea of nullability safely. It looks like this:

```
data Option a
= Some a
| None
deriving Show
```

We either have `Some`

value of type `a`

or we have `None`

.

Here’s the applicative (and functor) implementation for `Option`

:

```
instance Functor Option where
fmap f (Some a) = Some (f a)
fmap _ None = None
instance Applicative Option where
pure = Some
Some f <*> Some a = Some (f a)
None <*> Some _ = None
Some _ <*> None = None
None <*> None = None
```

The only way a computation for `Option`

can succeed is if we have `Some`

value along all paths. The moment we encounter a `None`

, we abort.

Let’s look at the implementation of `Alternative`

for `Option`

now:

```
instance Alternative Option where
empty = None
Some a <|> Some _ = Some a
Some a <|> None = Some a
None <|> Some a = Some a
None <|> None = None
```

In this case, we succeed as long as some computational path results in `Some`

. We fail only if all paths fail.

I’ll provide some examples next. A few notes:

`<$>`

is`fmap`

, or, the means to apply a pure function in a context`:{`

is used in the Haskell REPL to indicate multi-line input`:}`

terminates multi-line input

Here’s how what we’ve written looks like in use:

```
> (+) <$> Some 1 <*> Some 2
Some 3
> (+) `fmap` Some 1 <*> Some 2
Some 3
> (+) <$> Some 1 <*> None
None
> add3 a b c = a + b + c
> :t add3
add3 :: Num a => a -> a -> a -> a
> add3 <$> Some 1 <*> Some 2 <*> Some 3
Some 6
> add3 <$> Some 1 <*> None <*> Some 3
None
> None <|> Some 1
Some 1
> None <|> None
None
> None <|> None <|> Some 3
Some 3
> :{
| (+) <$> None <*> Some 1
| <|> (*) <$> Some 5 <*> Some 10
| :}
Some 50
> :(
| (*) <$> Some 8 <*> Some 5
| <|> None
| :}
Some 40
```

The examples above all use integers, but we could easily use any other type. Furthermore, notice that we can chain as many computations as we need, like with `add3`

. This is much more convenient than pattern matching on the spot every time, like:

```
add3OptLengthy :: Num a => Option a -> Option a -> Option a -> Option a
add3OptLengthy a b c =
case a of
None -> None
(Some a') -> case b of
None -> None
(Some b') -> case c of
None -> None
(Some c') -> Some (add3 a' b' c')
```

It is also less error-prone that using if-expressions, like so:

```
isNone :: Option a -> Bool
isNone None = True
isNone _ = False
-- dangerous
getOption :: Option a -> a
getOption (Some a) = a
getOption None = error "oh no crash"
add3OptUnsafe :: Num a => Option a -> Option a -> Option a -> Option a
add3OptUnsafe a b c =
if isNone a
then None
else if isNone b
then None
else if isNone c
then None
else Some (add3 (getOption a) (getOption b) (getOption c))
```

Alternatives and applicatives (and functors!) capture this logic for us so we don’t have to repeat ourselves. All of the above to say:

```
> f3 a b c = add3 <$> a <*> b <*> c
> :t f3
Num a => Option a -> Option a -> Option a -> Option a
```

Let’s look at a new context type now: `Xor`

`Xor`

(or it’s Haskell analogue, `Either`

) is a type used to store simple error information in the case of a failure. It looks like this:

```
data Xor a b
= XLeft a
| XRight b
deriving Show
```

The `XLeft`

branch is typically used to capture an error. The `XRight`

branch is our success path.

Here’s the implementation of `Applicative`

for `Xor`

:

```
instance Functor (Xor a) where
fmap f (XRight a) = XRight (f a)
fmap _ (XLeft a) = XLeft a
instance Applicative (Xor a) where
pure = XRight
XRight f <*> XRight a = XRight (f a)
XRight _ <*> XLeft a = XLeft a
XLeft a <*> XRight _ = XLeft a
XLeft a <*> XLeft _ = XLeft a -- choose the first error to short-circuit
```

As before, the only way to get to a success is to have successes all along the way.

`Xor`

does not admit an `Alternative`

instance. This is because, there is no reasonable definition of `Alternative`

’s `empty`

. If the left-branch type `a`

was a `Monoid`

, then it’d be possible to define, but it still wouldn’t be very interesting. We’ll elide that for now and show a more reasonable error-capturing type in the next section that allows for alternatives.

For the examples involving `Xor`

, we’ll first define a simple error data type with a few helper functions:

```
data NumberError
= NumberTooBig
| NumberTooSmall
| NumberNotAllowed
deriving Show
validateNumber :: Int -> Xor NumberError Int
validateNumber x
| x > 500 = XLeft NumberTooBig
| x < 30 = XLeft NumberTooSmall
| x `elem` [42, 69, 420] = XLeft NumberNotAllowed
| otherwise = XRight x
```

Now for some examples:

```
> validateNumber 32
XRight 32
> validateNumber 69
XLeft NumberNotAllowed
> validateNumber 501
XLeft NumberTooBig
> validateNumber 29
XLeft NumberTooSmall
> (+) <$> validateNumber 31 <*> validateNumber 33
XRight 64
> (+) <$> validateNumber 31 <*> validateNumber 42
XLeft NumberNotAllowed
```

Next, let’s look at an extension to the `Xor`

type - the `Validation`

type.

`Validation`

is a very handy type for any form of validation where you’d like to keep track of all errors that occur, instead of throwing them away. It looks fairly similar to `Xor`

, even:

```
data Validation a b
= Failure a
| Success b
deriving Show
```

Exchange `Validation`

with `Xor`

, `Failure`

with `XLeft`

, and `Success`

with `XRight`

and we’re right back to the last section! However, we’ll see that how we implement `Applicative`

and `Alternative`

can make a big difference.

Here’s the `Applicative`

implementation:

```
instance Functor (Validation a) where
fmap f (Success a) = Success (f a)
fmap _ (Failure a) = Failure a
-- accumulating errors
instance Monoid a => Applicative (Validation a) where
pure = Success
Success f <*> Success a = Success (f a)
Failure a <*> Success _ = Failure a
Success _ <*> Failure a = Failure a
Failure a <*> Failure b = Failure (a <> b)
```

The biggest change so far is that we require the error type to implement the `Monoid`

interface, which, expresses things that can be concatenated/merged/etc via the `<>`

operator. Instead of keeping only the first error encounterd, we keep them all. We’ll see how this works more closely with some examples soon.

Here’s the implementation for `Alternative`

:

```
instance Monoid a => Alternative (Validation a) where
empty = Failure mempty
Success a <|> Success _ = Success a
Success a <|> Failure _ = Success a
Failure _ <|> Success a = Success a
Failure _ <|> Failure a = Failure a
```

Nothing changed here compared to `Xor`

.

Before getting to examples, let’s define some convenient functions around our `NumberError`

data type from before:

```
numberTooSmall :: Validation [NumberError] a
numberTooSmall = Failure [NumberTooSmall]
numberTooBig :: Validation [NumberError] a
numberTooBig = Failure [NumberTooBig]
numberNotAllowed :: Validation [NumberError] a
numberNotAllowed = Failure [NumberNotAllowed]
validateNumberV :: Int -> Validation [NumberError] Int
validateNumberV x
| x > 500 = numberTooBig
| x < 30 = numberTooSmall
| x `elem` [42, 69, 420] = numberNotAllowed
| otherwise = Success x
```

And some examples:

```
> validateNumberV 32
Success 32
> validateNumberV 69
Failure [NumberNotAllowed]
> add3V a b c = a + b + c
> add3V <$> validateNumberV 32 <*> validateNumberV 33 <*> validateNumberV 34
Success 99
> add3V <$> validateNumberV 42 <*> validateNumberV 69 <*> validateNumberV 420
Failure [NumberNotAllowed, NumberNotAllowed, NumberNotAllowed]
> add3V <$> validateNumberV 42 <*> validateNumberV 10 <*> validateNumberV 50
Failure [NumberNotAllowed, NumberTooSmall]
> :{
(+) <$> validateNumberV 42 <*> validateNumberV 10
<|> (+) <$> validateNumberV 41 <*> validateNumberV 31
:}
Success 72
```

These examples are mostly silly, mainly for showing the mechanics, but the `Validation`

type is incredibly useful for giving thorough feedback to users when validating complex input. It often comes up in the context of web form validation (if working in a language like Purescript) where you want to check that all fields have sensible values, and if not, reporting what fields aren’t valid and why.

I’ll list two implementations below:

- Haskell validation
- Purescript validation

As this post has already gotten kind of long, I’ll leave several other amazing bits out of it for this time. The most useful bits I’m not bringing up, are that applicatives and alternatives can be used for:

- parsing
- text and bytestring formats: attoparsec
- complex text parsing, say, for programming languages: megaparsec
- JSON: aeson
- database fields: postgresql-simple
- command line options: optparse-applicative
- HTTP query params: wai-request-spec
- Though the servant package does this even more nicely with fancier techniques

- sequencing parallel code: parallel
- sequencing concurrent code: async
- even more

As a small example of applicatives and alternatives for parsing, here’s a bit of code from one of my projects that uses the attoparsec library noted above:

```
-- #SELECTABLE:YES
parseSelectable :: Parser Selectable
parseSelectable =
Selectable <$> (startTag *> parseSelect)
where startTag :: Parser Char
startTag = pound *> stringCI (tagBytes TNSelectable) *> char ':'
parseSelect :: Parser Bool
parseSelect =
(stringCI "YES" $> True) <|> (stringCI "NO" $> False)
```

The goal is to parse a string that looks like `"#SELECTABLE:YES"`

or `"#SELECTABLE:NO"`

, and having done so, wrap it in a type that differentiates it from a plain boolean type.

`*>`

is an applicative operator that performs parse sequencing, but discards the left-hand side. `$>`

is a functor operator that performs the effect to the left, and if successful, lifts the right-hand side into the current context.

`startTag`

matches the `"#SELECTABLE:`

portion, and `parseSelect`

looks for either a `"yes"`

or a `"no"`

in a case-insensitive fashion.

Probably the most interesting bit here is that I had the ability to specify alternative, valid parses using `<|>`

in `parseSelect`

. This comes in handy for parsing any sort of enumerated type, say, the error return code from a web API you’re consuming.

Anyway, that’s all! I hope this helped clarify what applicatives and alternatives are, and how you might use them. Even though this post is Haskell-centric, the core ideas can be expressed in other programming languages. Ultimately, applicatives and alternatives are just a safe, broad interface for composing computations with context and assigning rules to those contexts.

]]>It doesn’t assume you’ve used a typed programming language before. I’ll define things carefully and take care with jargon. I’ll give priority to concrete examples, so that you can use this to build things. It’s important to me that this can be a post you can come back to if you want to get more comfortable with typed programming and have the time and energy for it.

Types and type systems are powerful tools, and I want to make them a little easier to use. They’re great for communication, for expression, for correctness, for program maintenance, and peformance. The problem is, how do we use them well?

All examples will be given using the Haskell programming language. It’s pretty easy to install nowadays, and the syntax is pretty clean for talking about type system things.

Types are, a lot of things. If I were to give an overarching definition, they’re at the very least, a way to describe the shapes of data and programs.

There’s a lot of context, often times left unsaid when folks talk about “types”, unqualified.

Some people talk about types and think of **storage** types. These describe how much space certain pieces of program take up in memory, and possibly, how that data is interpreted. Think: integers, longs, unsigned integers, floats, arrays, C.

Some people talk about types, and object-oriented design comes to mind. These sorts of types are one system for classifying data that mixes state, scope, and behavior together, and talks about types in terms of hierarchies of capabilities. These are known as **sub-type** systems. Think: Java, C Sharp, classes. This post is not about these systems.

Others still, talk about functional programming, and algebraic types, and a bunch of other things, sometimes of a very mathematical nature. There’s talk of how to compose things, how functions interact, and about side-effects and types to describe them. Think: Haskell, Elm, monads, and the like. This post is about these sorts of type systems, and how to understand and think about them. Let’s call them, **algebraic data** types.

Further still, some folks talk about types for proving whole programs adhere to specs. At this point, we’ve wandered into **dependent** types, provers, and type theory. While these systems can be extremely expressive, they’re outside the scope of this post. We’re starting small, to be able to read and make sense of things we can use right now.

There’s also the distinction between **dynamic** and **static** types. When I talk about dynamic type systems here, I’m talking about Python, Ruby, Racket, Javascript, Erlang, and others like them, who check the types of data at run-time. Some are more strict than others. Static type systems run all their checks at compile time, before a program is ever run. That’s what languages like Java, C, C++, Rust, Haskell, and OCaml do. Like the dynamic case, there’s sharp differences about what sorts of things each of these languages can check, some strictly more expressive than others.

Speaking of expressivity - I use this term in a strict sense, which I’ll make more clear with the rest of this post, this post about reading and understanding types. An expressive type system is one that let’s you say more about your data, without much hassle. These are the best sorts of type systems for communicating intent about your programs and data.

That’s “types”. “Types”, as it turns out, can mean a lot of different things to different people.

Given all the definitions up to this point, let’s talk about something more concrete: type signatures.

A type signature is a description of a function:

- what it’s name is
- what parameters it takes and their shapes
- the shape of what it returns

A lot of information can be packed into a small space. Type signatures are the first place to look to try to understand a function.

Type signatures are the main thing we’ll be working to understand how to read.

Here’s a type signature now:

`add :: Int -> Int -> Int`

`add`

is a function that takes two `Int`

arguments and returns an `Int`

. More generally:

```
someFunction :: -- function name
a -> b -> c -- function parameters/arguments
-> d -- return type
```

Of course, different languages have different ways of expressing types signatures. Here’s `add`

in C:

`int add(int x, int y);`

Here’s `add`

in Scala:

`def add(x: Int, y: Int): Int`

We’ll look at far more interesting type signatures later as we build on what we know.

Primitive types are those provided by a language that are closest to what might be stored on a machine. Things like:

- integral types: 1, -1, 10
- decimal types, doubles and floats: 1.0, 2.31212, 3.1415926
- text: “cat”, “girls”, “are”, “great”, “actually”, “”
- bytes: [0x01, 0x05, 0x19]
- bool: true, false
- unit: () – literally the type that only has one value, ()

In Haskell, these types are:

- Int
- Integer (to represent numbers that are too big to fit in a register)
- Float
- Double
- String (sort of - it’s a doubly-linked list of characters)
- Text
- ByteString
- Bool
- ()

There are also types that can express functions, specifically, functions as arguments to other functions.

Let’s look at an example:

```
addAndShow :: Int -> Int -> (Int -> String) -> String
showInt :: Int -> String
```

This is almost `add`

, but with more power. It now takes a function paramter that let’s us turn an integer into a string. Looking immediately below, we have such a function handy. Let’s go even more concrete for a moment. Here’s the **definition** of `addAndShow`

:

`addAndShow x y showFn = showFn (x + y)`

That’s all there is to that one. Below, I’ll show what a definition of `showInt`

might look like. A few notes before I get to it:

- such a function is already provided by the standard library:
`show`

- it introduces a lot of new syntax
- the implementation is recursive
- it’s not necessary to understand what function types mean

With that said, for the curious:

```
showInt :: Int -> String
showInt n =
let n' = abs n in
let ret = go (n' `div` 10) (n' `mod` 10) [] in
if n < 0 then '-' : ret else ret
where go :: Int -> Int -> String -> String
go leftDigits rightDigit acc
| leftDigits == 0 && rightDigit == 0 = acc
| otherwise = go (leftDigits `div` 10) (leftDigits `mod` 10) (toChar rightDigit : acc)
toChar :: Int -> Char
toChar x = case x of
0 -> '0'
1 -> '1'
2 -> '2'
3 -> '3'
4 -> '4'
5 -> '5'
6 -> '6'
7 -> '7'
8 -> '8'
9 -> '9'
_ -> error "out of bounds - toChar, Int not between 0 - 9"
```

It is important to note also that at this point, we don’t have enough tools to give really precise types. Notably, let’s look at another function that fits `(Int -> String)`

, but doesn’t do what we’d hope:

```
showInt2 :: Int -> String
showInt2 _ = "2"
```

This definition **does** satisfy the given type signature. Sure. But! This warning is here specifically to emphasize the limits of what we can express at this point. We know that:

- we have one and only one argument: an
`Int`

- it returns a
`String`

- never anything else - no side-effects will be performed (more on that later)

Reading type signatures and designing types is every bit as much about what functions can do as it is about what functions **cannot** do. Keep this in mind as we proceed.

Let’s expand what we can express with types in the next section.

Most code examples will be given using Haskell. When an example uses another programming language, I’ll call that out before showing the example.

The advice is focused on languages that have a compile-time type-check step, but can be informally adopted to make maintenance of dynamically-typed programs (Javascript, Python, Ruby, etc.) a little easier.

When I talk about the size of types, I’m talking about how many values a given type can represent. A few examples:

- boolean: true or false, a type of size 2
- 32-bit integer: 2^32 possible values, a type of size 2^32
- a string, encoded as a byte array: 2^8 * n, n being the length of the string
- a type of infinite size, for our calculations

These examples are all primitive types. Fortunately, most programming languages offer at least some form of abstraction over these primitive types. Leveraging those abstractions will allow us to craft types that are smaller than the primitive types, and can therefore more accurately describe our domain of interest.

In particular, I want to talk about algebraic data types. They’re called as such because in a sense I’ll make clear soon, they allow us to add to and multiply a type space to meet our needs as precisely as possible.

For example, a sum type `Color`

:

`data Color = Red | Green | Blue`

This type has 3 values, or variants: `Red`

, `Green`

, `Blue`

. It’s a sum type, because each variant adds 1 one more value to the size of the type. With that, `Color`

is a type of size 3. This is a reliable fact as long as implicit conversion isn’t something to watch for in your programming language of choice. More on that later.

In Scala, this might look like:

```
sealed trait Color
final case object Red extends Color
final case object Green extends Color
final case object Blue extends Color
```

Most mainstream languages have basic support for sum types, via enumerations. However, sum types become particularly interesting when used with product types. A product type might look something like:

```
data AreaColor = AreaColor { inverted :: Bool, color :: Color }
-- basic shape: AreaColor Bool Color
```

An `AreaColor`

has 2 * 3 possible values. Let’s enumerate them.

```
> let ct0 = AreaColor True Red
> let ct1 = AreaColor True Green
> let ct2 = AreaColor True Blue
> let cf0 = AreaColor False Red
> let cf1 = AreaColor False Green
> let cf2 = AreaColor False Blue
```

Most mainstream languages have excellent support for product types. You may have heard them referred to by the names, “struct”, “record”, or the like. The components of the product type multiply together to give the new type size.

Here’s where most mainstream programming languages falter: being able to combine sum and product types conveniently.

Here’s an example of the two used together:

```
data PaletteCommand
= ClearPalette -- 1
| AddColor Color -- 3
| SwapColor Color Color -- 3 * 3
| InvertPalette -- 1
-- total size: 1 + 3 + 9 + 1 = 14
```

`PaletteCommand`

is a toy example of the sorts of concepts that can be expressed when you have algebraic data types.

It’s very powerful being able to conveniently combine sum and product types. So much so, that without this ability, it becomes very easy for the complexity of a program to multiply. This is what I meant when I said 2 years ago that “In languages lacking sum types, the complexity of a program can only multiply”. ref

Now we have just enough of the basics of calculating the size of types so that we can talk about dealing with how to resolve design problems.

One of the most common design problems that one might encounter when working with existing code is that everything will be expressed and encoded as a string, e.g., a so-called stringly-typed code base. This can happen in any programming language. After all, strings are nearly always provided as a primitive type. It might come up in the context of retrieving data from a database to affect control flows, as messages from a queuing system, as commands from a network-connected client, or even as commands from a command line interface.

Below, I’ll show some of the trouble with relying on strings to handle program control flow.

Let’s write a function, `colorToInt`

, that given a string, returns a numeric representation of that color:

```
colorToInt :: String -> Int
colorToInt c =
case c of
"red" -> 0
"green" -> 1
"blue" -> 2
```

And an example of where this goes wrong:

`main = print (colorToInt "Red")`

This will raise an exception. Our `colorToInt`

function doesn’t know how to handle `"Red"`

. A first-pass at fixing this might be something like:

```
-- toLower: String -> String, makes it lower-case
colorToInt2 :: String -> Int
colorToInt2 c =
case toLower c of
"red" -> 0
"green" -> 1
"blue" -> 2
_ -> 3
```

Now, our former example works alright. But what about:

```
main = do
print (colorToInt2 "Reed")
print (colorToInt2 "Bleu")
print (colorToInt2 "Gren")
```

These all return `3`

, which amounts to an unknown color value. A third and common pass might throw an exception:

```
colorToInt3 :: String -> Int
colorToInt3 c =
case toLower c of
"red" -> 0
"green" -> 1
"blue" -> 2
_ -> error ("unknown color " ++ c)
```

This will catch all typos. But - how does it fare in the face of program updates?

Let’s assume we have a `morbidify`

function defined deep in our system. It’s worked for a long time, and no one’s thought about it for months because there’s been other priorities in mind.

```
morbidify :: String -> Int -> DbConnection -> IO ()
morbidify c userId databaseConn = do
let colorValue = colorToInt3 c
setFaveUserColor c userId databaseConn
```

New requirements come in: Red in no longer supported and now we need to add Cyan.

We remember to update `colorToInt3`

:

```
colorToInt3 :: String -> Int
colorToInt3 c =
case toLower c of
"cyan" -> 0
"green" -> 1
"blue" -> 2
_ -> error ("unknown color " ++ c)
```

But somewhere in the system, the following call occurs:

```
...
morbidify "red" userId dbConn
...
```

Suddenly, this call will start to fail. Given the nature of the code, one that performs a side-effect on behalf of the system, it is very unlikely that tests will have been written for this. If we’re somewhat fortunate, someone thought to add some logging to `morbidify`

, so at least the problem will be detected and can be explained. If we’re not so lucky…

Well, the good news is we can do much better than this. Let’s talk about it next.

Many of the problems we ran into the last section were because the size of string types is far too large. Let’s see how using sum types can make the situation better. First, we start with a few definitions:

```
data Color = Red | Green | Blue
colorToInt4 :: Color -> Int
colorToInt4 c =
case c of
Red -> 0
Green -> 1
Blue -> 2
```

Let’s play around with this a little. First, our failing examples from before:

`main = print (colorToInt4 "Red")`

This gives us a compile-time error, noting that we expect a `Color`

but got a `String`

`main = print (colorToInt4 Reed)`

This gives us a compile-time error, noting that the value `Reed`

is unknown.

Let’s add support for `Cyan`

:

`data Color = Red | Green | Blue | Cyan`

And a small test program:

`main = print (colorToInt4 Cyan)`

This gives us a compile-time **warning** that `Cyan`

wasn’t handled in `colorToInt4`

. This is a cool thing known as **exhaustivity analysis**, a super helpful thing a few languages containing full support for sum types can do.

Let’s remove support for `Red`

and `Cyan`

:

```
data Color = Green | Blue
main = print (colorToInt4 Cyan)
```

This will give us two compile-time errors:

- we mention
`Cyan`

in`main`

when we’ve never defined it - we mention
`Red`

in`colorToInt4`

when we’ve not defined it

This is the basic premise behind using small types as a tool for making programs easier to maintain. If the size of our types is as small as possible, while still fully expressing our domain, errors cannot be represented.

Now let’s talk about caveats and things to watch for.

Implicit conversion. Sometimes, we try as hard as we can, and the programming languages we use try to be as helpful as they can, and things Just Go Wrong.

This is particularly notable in Java and Scala, where `toString`

is defined over all types.

The problem arises when interfacing with legacy code, where most of the types are still the infinitely-sized `String`

instead of our constrained `Color`

. We might pass in a `Color`

to such a legacy function, and expect the compiler to flag us somehow, but it silently gets converted to a String. Where we expected to be able to reason about a type that is at most size 3, we’re back to the land of infinites.

Another problematic conversion that is fairly common, is one of most primitive types to `Bool`

. This will sometimes come up in control paths, where an if-statement is used to determine what’s to be done next, rather than a switch. The problem here is that we’re defined fine-grained control with our type, say `Color`

, of size 3, but we’ve shrunken down to something that can only express 2 paths, `Bool`

.

Another common implicit conversion to watch for is that of enumeration to integer. This happens in C, and when using regular enumerations (rather than `enum class`

) in C++.

For languages (frequently object-oriented languages) that have a notion of value and reference types, and of nulls, beware of the possibility of `null`

inhabiting your type. It is entirely possible in `Scala`

and `Java`

for `null`

to be a member of our `Color`

type, and still cause us trouble.

There’s a few other forms of implicit conversion to worry about. It all depends on your domain and the programming language you’re working with. They’re beyond the scope of this post.

In sum, watch out for:

- implicit string conversions, particularly in Java and Scala
- implicit conversion to Bool at control paths
- implicit conversion from enumeration to integer, particularly in C and C++
- nulls, because they break everything

It’s worthwhile to keep in mind the danger of implicit conversions when relying on the size of types to design your programs.

To wrap up, I’ll leave you with a few practical tips.

Make the types at the core of your program as small as possible.

The best time to shrink a type is as early as possible. By this I mean, if you’re interfacing with the outside world, say, reading an environment variable or parsing some user input, that is the time to determine whether the input is valid and make a value of your small type or return some form of error. `Either`

and `Maybe`

types are lovely here.

The best time to grow your types again is when outputing at the boundaries of your programs. Serialize them as needed, and send them off to the database as a String field or as a response to a client command as a part of a JSON blob.

Sometimes, there’ll be data that really needs to be a `String`

or an `Int`

, and can’t be shrunk. This will be safe to do as long as no control paths depend on the shapes of the values contained in the `String`

or `Int`

. If you notice the flow of your program start to depend on what’s in those strings or integers, it might be time to consider shrinking to a more representative type.

That’s the basic idea.

We’ve covered a lot in this post. However, there’s still a whole lot more to explore when it comes to using the size of types to design programs. Here’s a selection of things I didn’t cover that might be of interest:

- size of polymorphic types:

`f :: (b -> c) -> (a -> b) -> (a -> c)`

- size of functions and their compositions
- size of subtypes (Scala, Java, etc.):

`ExtendedColor <: Color`

- size of constrained types:

`(Show a, Random a) => a -> Maybe a`

- typed holes
- limits of exhaustivity analysis
- reasoning about the size of effectful functions:

`g :: Color -> Url -> Database Response`

- using the size of types for automated linting and static analysis

Anyway, enjoy your small types. ❤

]]>This will be a series of posts covering the development of a Domain Specific Language for search. I’ll dive into the design, testing, and implementation of parsing and evaluation. This will include both pure evaluation and compilation to express queries for an external data store (*SQL, Elastic Search, etc.).

In part 1, I’ll cover why someone might want to use a DSL, as well as the design and implementation of the DSL core.

Why would you want to implement a DSL?

Focusing on search, you might want to expose search functionality to users. This might be a public-facing, HTTP API that allows users to look up other user details and posts, like Twitter’s Search API. You might be part of a team at a large Cloud Services provider, putting together a search engine for users to review logs regarding infrastrcuture. This might an internal feature, an enhancement to existing developer tools to facilitate handling customer support requests.

Search is a wide space!

The main reasons to pursue a DSL as a solution are:

- You need a precise language for describing allowed operations
- The language must be expressive and relevant
- Extensions to the language should be possible to meet changing needs
- The system should be helpful, letting users know if something was incorrect
- The backend should be swappable
- The frontend should be swappable
- The system needs to be well understood, with no edge cases

Essentially, DSL approaches to solving problems bring the capabilities of language design theory to your problem space.

It’s notable that command line tools like **grep**, **sed**, **awk**, and **find** are themselves DSLs. A surprising number of problems can be approached with language design techniques in mind.

While there are many benefits to such an approach, it is not without costs. The primary costs are knowledge and time - knowing enough about language design, parsing, and the domain to bring together the pieces, and having enough time to make it all work.

This series of posts aims to address the knowledge part of the cost, by demonstrating what this process looks like from start to finish.

Let’s get into it!

We’re going to start with a simple search language and build on it in later posts. Let’s first specify a few parts of the language, enough to perform some interesting searches:

- operations:
`<`

,`>`

,`==`

,`>=`

,`<=`

- types:
`int`

,`bool`

,`str`

- variables/identifiers
- basic type-operation constraints:
`Ordering`

,`Equality`

- logical combinators:
`and`

This allows for expressions like:

```
confidential == false
count > 10 and ip == "10.0.8.0"
date >= "2010-10-12" and date <= "2010-11-12"
```

Future extensions to the language could happen along any of the above axes: more operations, more types, more type constraints, more logical combinators.

For a convenient implementation, the limiting factor is how much the host programming language’s type system can accommodate. I’ll be using Haskell in this series, but any language that allows for algebraic data types should be enough to reproduce this work. It’s entirely possible to develop a DSL solution in other languages, but there’ll be more testing to do.

Let’s implement the language core.

We’d like to support all of `<`

, `>`

, `==`

, `>=`

, `<=`

. Let’s add those in:

```
data Op
= Lt -- <
| Gt -- >
| Eq -- ==
| Gte -- >=
| Lte -- <=
deriving Eq
```

Next, we’ll add support for types and values:

```
data Type
= IntType
| StringType
| BoolType
deriving Eq
data Literal
= IntLit Int
| StringLit Text
| BoolLit Bool
deriving Eq
```

Notice that we’re maintaining both type-level and value-level information, and maintain a distinction between the two levels.

Next up, support for variables:

```
type Var = Text
type Field = (Var, Type)
type Env = [Field]
```

This is a fairly straightforward approach. We don’t have to worry about bindings or scope. We leave the declaration of allowed variables to the search engine provider, to be exposed via documentation.

Next up: type constraints!

```
data Supports
= Equality
| Ordering
deriving (Eq, Show)
supports :: Type -> [Supports]
supports IntType = [Equality, Ordering]
supports StringType = [Equality, Ordering]
supports BoolType = [Equality]
needs :: Op -> [Supports]
needs Lt = [Ordering]
needs Gt = [Ordering]
needs Eq = [Equality]
needs Gte = [Ordering, Equality]
needs Lte = [Ordering, Equality]
-- > IntType `can` Lt
-- True
can :: Type -> Op -> Bool
can t op = null (needs op \\ supports t)
```

Next, the logical combinator `and`

. I’ll also introduce how binary operations are represented at this stage:

```
data Expr
= And Expr Expr
| BinOpL Op Var Literal
| BinOpR Op Literal Var
deriving (Show, Eq)
```

This little recursive data type captures the essence of our language. Let’s break it down:

`And Expr Expr`

:`and`

combines two expressions`BinOpL Op Var Literal`

: a binary`Op`

with a`Var`

on the Left and a`Literal`

`BinOpR Op Literal Var`

: a binary`Op`

with a`Var`

on the Right and a`Literal`

With this construction, we’ve ruled out some cases:

- An expression can never consist of two literals:
`1 < 2`

- An expression can never consist of two vars:
`date == date`

,`ip > date`

- A single expression will never have more than one operator

Here’s the language as a whole, for convenient reading:

```
data Op
= Lt -- <
| Gt -- >
| Eq -- ==
| Gte -- >=
| Lte -- <=
deriving Eq
data Type
= IntType
| StringType
| BoolType
deriving Eq
data Literal
= IntLit Int
| StringLit Text
| BoolLit Bool
deriving Eq
data Supports
= Equality
| Ordering
deriving (Eq, Show)
supports :: Type -> [Supports]
supports IntType = [Equality, Ordering]
supports StringType = [Equality, Ordering]
supports BoolType = [Equality]
needs :: Op -> [Supports]
needs Lt = [Ordering]
needs Gt = [Ordering]
needs Eq = [Equality]
needs Gte = [Ordering, Equality]
needs Lte = [Ordering, Equality]
-- > IntType `can` Lt
-- True
can :: Type -> Op -> Bool
can t op = null (needs op \\ supports t)
data Expr
= And Expr Expr
| BinOpL Op Var Literal
| BinOpR Op Literal Var
deriving (Show, Eq)
```

That’s all I’m going to cover for now - the core of the language. In the next post, I’ll build a parser for this language and write some tests for that parser.

If you’d like to get a head start, the source for the search DSL is availaible in this GitLab repo.

Thanks for reading!

If you enjoy my works:

]]>If you’d like to help me, please consider donating to my Patreon.

I write Haskell, primarily. I’ve written quite a bit of it. You can see a sampling of that work on my Gitlab. You may also turn to my resume for additional pointers.

I specialize in backend and systems work. I’m comfortable with implementing components of projects, as well as full projects.

I can also teach, write, and draw. I use a combination of those skills to communicate, express ideas, and make concepts more accessible.

I am an intersectional feminist. This means that my works try to take into account the needs of all people, but especially those that are being hurt by our current systems.

- I will not work on secret or proprietary software
- I will not work on secret or proprietary research
- I will not patent my original works
- I will enforce a code of conduct on my projects
- I will work on software projects available to all
- I will work on software with licensing approved by OSI
- I will release my own software under such licenses
- I will create other works under the CC-BY license
- I may refuse to work on projects with toxic maintainers or communities
- Consent first: our terms must be mutually agreeable
- I expect to be paid for my labor
- None of the above is negotiable

- They gave a short overview of the program
- They paired me with legal students
- They began the process of filling out the relevant petitions
- They made copies of necessary documents
- They gave me a take-home list of docs I still needed
- They’ll keep in touch during the process and help guide it to completion

I asked about support for non-binary gender identities. As I expected, there is no such support in the United States of America. You pretty much choose M or F. It’s amazing how much pressure this puts on individuals to “sort” into the binary. More on that some other time.

Here’s the sorts of documents needed for completing the process:

- Social security card
- Birth certificate
- Letter from therapist
- Letter from physician
- State issued ID
- Fingerprint card

There seems to be additional documentation needed if you’ve changed your name before or if you’ve got a criminal record.

They reassured listeners that the judges in Austin, TX would not have an adversarial hearing. That’s to say, they won’t ask you why you’re doing this, what your gender is, etc. They’ll review your petition beforehand, and then you just need to be present in order to answer questions about missing documentation or documentation that needs clarification.

Another detail: as a resident of TX, you can choose any county in TX to undertake the procedure. Austin, TX rates favorably, based on information I overheard at the workshop. Also, if you were born in TX, but then move to another state, you can still complete this process in TX, even as a non-resident.

The expected fees for the full process are around $300-$400. These fees can be waived if you show that you’d be unable to pay them.

The most tedious process really seems to be about the aftermath - everything **ELSE** you need to change after getting legal recognition from the local government. For me, that amounts to at least:

- Marriage license
- Lease
- Vehicle registration
- Social security
- Driver’s license
- Business ownership
- Bank accounts
- Credit reporting agencies

That’s the gist of things. The Q hosted the workshop, and they seem pretty great.

So with that, my name will be Allele Dev in probably about three to four months, and my gender marker will be F.

]]>I’ve worked in tech for almost three years now. The first year was the best, and things gradually went down hill from there. A few factors were at play in that decline.

My awareness of myself and the world around me was **really** low in 2012. Honestly, I didn’t know much about who I was, what I believed in, or where I was going. I just knew I had to get out of college, and that getting paid was a Good Thing.

At the time, I had no idea I was trans. I didn’t even know it was a thing I could be. I’m suspect I had some white, male-passing privilege helping me along. By the time April 2014 rolled around, I knew I was trans - I was out soon after that. Things gradually got worse at work, as I presented more and more femme, especially in 2014. 2015 was better, in this regard. Still, for every job after my first, I was the only woman on the teams I was assigned to. It’s really alienating to be the only trans person, the only woman, the only X - in any team situation.

Awareness - that spiked pretty quickly after I realized I was trans. I learned about all the different ways people are marginalized and oppressed, that there are irrefutable, intersectional systems that keep people down. Twitter played a significant role in my awareness increasing over time. I saw painful situations unfolding in real time. I listened carefully to people expressing their lived experiences. The first few months of analyzing my privilege were **very** uncomfortable. It still can be uncomfortable when I run into something I haven’t introspected on before. That got easier. It gets easier.

I couldn’t help but see those structures of oppression paralleled in every job I had. Expectations of long hours, more hours than my health could handle. Credit being taken by company “leadership” for the efforts of the workers. Blame being put on the workers when things didn’t work out as planned. Punishment for the workers when they spoke up about things being shitty, unrealistic, or unreasonable. I didn’t spend much time blaming individual actors, except for a few particularly toxic examples. The non-toxic participants were caught up in these sytems, and they need to make a living, too. My goals were fundamentally misaligned with things like *Delivering Business Value*, *Minimum Viable Products*, *Profits*. I’m not suited to quietly working in companies that want to keep to the exploitative status quo.

In a sense, all that time I’d been working (n+1) jobs: the 1 salaried, the remaining **n**, unpaid labor. Things like: writing articles about tech, taking **extra** time and care to ensure the things I made in my day job were of high quality and maintainable, publishing and maintaining open source libraries, crafting tutorials, following and reporting on tech trends. Others have written about all this before, several people, at different times - Unpaid Labor.

Taking inspiration from articles like this one on wages in tech, or this one, and realizing I couldn’t end Capitalism over night or escape it, I decided to seek my own path. I wanted to find a way to: work on my terms, with my ethics and capabilities in mind, and make it sustainable. If anything, that’s the origin story for Queer Types, at least three years in the making.

I want to use the skills I have to help make the world a better place. I also want it to be on my terms.

Some terms I’ve set for myself:

- I will not work on secret or proprietary software

I’ve spent enough time rebuilding CRUD app #37. At large, it’s also notable that we have more than 5 SQL databases, more than 4 web browsers, probably more than 20 text editors, and so on. There’s a lot of repetition, and for what?

I can understand the need for customization and tailoring tools for specific problems. However, what we have as a consequence of copyright and profit-driven-development is a rebuilding of the same fundamental things, over and over again. This is not a technical problem, this is a socioeconomic problem.

I want to avoid contributing to that senseless duplication.

- I will not work on secret or proprietary research

Similarly, for research. Knowledge should flow as freely as possible. It’s easier than ever now, too.

- I
**will**work on software projects available to all

Generally, this means that the source is available and the licensing aligns with the goal of keeping the projects available to all.

- I
**will**make all my written works freely available

As with software. Yes, this includes books I intend to write.

- I expect to be paid

See the origin story in the previous section. That I want to provide freely available works doesn’t mean I’ll allow myself to be exploited. I have to live, too. I do not condone Unpaid Labor, **especially** in a society that still thinks it’s right for people to have to Earn Their Right to Live.

- Consent first

I’ll be working with others. I’ll respect their terms, too, and if they align, we can work together.

Phrased differently, what can I do? I can write software, technical articles, tutorials, and books. I can also teach, make art, and consult.

So, keeping the terms and boundaries above in mind, I hope to offer the following services through Queer Types:

- Technical writing
- Technical workshops
- Written tutorials
- Software: implementation, design, testing, benchmarking
- Drawing: cute things, technical things, cute & technical things
- Awareness & advocacy

Notably, for drawings, this would go great with Patreon-acquired funding as a reward. You like what I do, I write you a small program, and then send you a hand-made drawing involving that program. We celebrate, because things are cute, and we both learn things. This line of thinking was inspired by sailorhg’s work on Bubble Sort zines. There’s no reason tech can’t be cute. ❤

On tech work specifically, I have no intention of covering the full software market. I know my specialties and preferences. I love typed, functional programming. I like backend and systems work, and I want to like frontend work. Technology-wise, this amounts to work involving some mix of:

- Linux
- Haskell
- PureScript
- Idris
- Rust, maybe

Projects like Support JSON errors for PureScript (or other error reporting enhancements), improvements to cabal or stack, and other infrastructural/library work around any of the above languages, would be suitable for me.

So then, what do I do, and how do I maintain my terms and beliefs while I’m at it? It’s still a bit of an open problem, to be honest. My first two plans, both with short-comings:

- Start a Patreon for my month-to-month efforts
- Start a KickStarter/IndieGogo campaign for book work

Patreon mostly works, especially for requesting donations in exchange for cute things. The primary shortcoming is in the allocation of my resources (hours I can work per month) to various “rewards” tiers for larger scope work.

For example, I can create a reward tier for $1200/month that serves as a promise to a particular funder that I will work on a mutually-agreed project for 4 days. If I introduced more levels (more money, more promised days), the limit system fails me, because it works in terms of rewards given, rather than the global hours-I-can-work-per-month resource. Example:

- 10 slots: $600/month for 2d of project work
- 5 slots: $1200/month for 4d of project work

I can end up overcommitted with:

- 4 instances of $600/month: 8d of work
- 4 instances of $1200/month: 20d of work
- Total: 28d of work

Also, things like:

- Negotiating projects with potential funders (accept/reject/clarify/allocate)
- Scheduling/managing projects (in progress/outcome reporting/pending)

would have to happen out-of-band. Might be a worthwhile weekend project to scrap together a site that interacts with a service like Stripe for payment processing but also gives me (and funders) the ability to visibly negotiate and track projects. I dunno. Open problem!

The IndieGogo campaign may be the best short term path. I have plans to write an accessible book on **Haskell Web Development**. I’d ask for $20000 as a minimum marker for writing such a book over a period of 3 months. That’d cover the cost of living for longer than 3 months, and there’d likely be weekly chapter releases, so funders can watch the book grow over time. Stretch goals would cover additional topics, additional mediums (screen casts?), and possibly an additional book (anything past the $60,000 mark).

Keeping with the previous section on my terms, the book would be freely available. It’d be akin to Real World Haskell or PureScript by Example - people can choose to pay for print copies, and Amazon/LeanPub/etc. can provide them, but the sources to build PDFs/etc. and run code will always be available in some source control repo. Also akin to the Bandcamp model for artists, where some works are offered on a “Name Your Price” basis: you can download it for free if you like, but if you’re able, donations are welcome.

Another possibility for funding would be to look towards something like Ruby Together. It seems that the Industrial Haskell Group is the closest analogue to this in Haskell land. It doesn’t sound anywhere near as appealing or welcoming as the Ruby Together effort. Maybe there’s room for another such organization? I don’t know. More open problems!

That’s the gist of it. I don’t want to work in our current systems, I want to set my boundaries, and I have a plan.

Next steps: figure out funding. You’ll all hear about that part pretty soon.

Long term goals: end capitalism?

]]>`ghc-base-78-to-710.diff`

. The information inside turned out to be pretty interesting. I figured I’d throw it up here in case it’s of use to anyone.
Below is a summary of all the changes to the `base`

library from GHC 7.8 to 7.10, by module, in diff format:

```
Control.Monad
+ (<$!>) :: Monad m => (a -> b) -> m a -> m b
- class Monad m
+ class Applicative m => Monad m
- class Monad m => MonadPlus m
+ class (Alternative m, Monad m) => MonadPlus m
- foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
+ foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
- foldM_ :: Monad m => (a -> b -> m a) -> a -> [b] -> m ()
+ foldM_ :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m ()
- forM :: Monad m => [a] -> (a -> m b) -> m [b]
+ forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
- forM_ :: Monad m => [a] -> (a -> m b) -> m ()
+ forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
- guard :: MonadPlus m => Bool -> m ()
+ guard :: (Alternative f) => Bool -> f ()
- mapM :: Monad m => (a -> m b) -> [a] -> m [b]
+ mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
- mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
+ mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
- msum :: MonadPlus m => [m a] -> m a
+ msum :: (Foldable t, MonadPlus m) => t (m a) -> m a
- sequence :: Monad m => [m a] -> m [a]
+ sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
- sequence_ :: Monad m => [m a] -> m ()
+ sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
- unless :: Monad m => Bool -> m () -> m ()
+ unless :: (Applicative f) => Bool -> f () -> f ()
- when :: Monad m => Bool -> m () -> m ()
+ when :: (Applicative f) => Bool -> f () -> f ()
Data.Bits
+ countLeadingZeros :: FiniteBits b => b -> Int
+ countTrailingZeros :: FiniteBits b => b -> Int
+ toIntegralSized :: (Integral a, Integral b, Bits a, Bits b) => a -> Maybe b
Data.Monoid
+ Alt :: f a -> Alt f a
+ getAlt :: Alt f a -> f a
+ newtype Alt f a
Data.List
- all :: (a -> Bool) -> [a] -> Bool
+ all :: Foldable t => (a -> Bool) -> t a -> Bool
- and :: [Bool] -> Bool
+ and :: Foldable t => t Bool -> Bool
- any :: (a -> Bool) -> [a] -> Bool
+ any :: Foldable t => (a -> Bool) -> t a -> Bool
- concat :: [[a]] -> [a]
+ concat :: Foldable t => t [a] -> [a]
- concatMap :: (a -> [b]) -> [a] -> [b]
+ concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
- elem :: Eq a => a -> [a] -> Bool
+ elem :: (Foldable t, Eq a) => a -> t a -> Bool
- find :: (a -> Bool) -> [a] -> Maybe a
+ find :: Foldable t => (a -> Bool) -> t a -> Maybe a
- foldl :: (b -> a -> b) -> b -> [a] -> b
+ foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
- foldl' :: (b -> a -> b) -> b -> [a] -> b
+ foldl' :: Foldable t => (b -> a -> b) -> b -> t a -> b
- foldl1 :: (a -> a -> a) -> [a] -> a
+ foldl1 :: Foldable t => (a -> a -> a) -> t a -> a
- foldr :: (a -> b -> b) -> b -> [a] -> b
+ foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
- foldr1 :: (a -> a -> a) -> [a] -> a
+ foldr1 :: Foldable t => (a -> a -> a) -> t a -> a
+ isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool
- length :: [a] -> Int
+ length :: Foldable t => t a -> Int
- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ mapAccumL :: Traversable t => (a -> b -> (a, c)) -> a -> t b -> (a, t c)
- mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ mapAccumR :: Traversable t => (a -> b -> (a, c)) -> a -> t b -> (a, t c)
- maximum :: Ord a => [a] -> a
+ maximum :: (Foldable t, Ord a) => t a -> a
- maximumBy :: (a -> a -> Ordering) -> [a] -> a
+ maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
- minimum :: Ord a => [a] -> a
+ minimum :: (Foldable t, Ord a) => t a -> a
- minimumBy :: (a -> a -> Ordering) -> [a] -> a
+ minimumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
- notElem :: Eq a => a -> [a] -> Bool
+ notElem :: (Foldable t, Eq a) => a -> t a -> Bool
- null :: [a] -> Bool
+ null :: Foldable t => t a -> Bool
- or :: [Bool] -> Bool
+ or :: Foldable t => t Bool -> Bool
- product :: Num a => [a] -> a
+ product :: (Foldable t, Num a) => t a -> a
+ scanl' :: (b -> a -> b) -> b -> [a] -> [b]
+ sortOn :: Ord b => (a -> b) -> [a] -> [a]
- sum :: Num a => [a] -> a
+ sum :: (Foldable t, Num a) => t a -> a
+ uncons :: [a] -> Maybe (a, [a])
Foreign.Marshal.Alloc
+ calloc :: Storable a => IO (Ptr a)
+ callocBytes :: Int -> IO (Ptr a)
Foreign.Marshal.Utils
+ fillBytes :: Ptr a -> Word8 -> Int -> IO ()
Foreign.Marshal.Array
+ callocArray :: Storable a => Int -> IO (Ptr a)
+ callocArray0 :: Storable a => Int -> IO (Ptr a)
Control.Exception.Base
+ AllocationLimitExceeded :: AllocationLimitExceeded
+ data AllocationLimitExceeded
+ displayException :: Exception e => e -> String
Control.Exception
+ AllocationLimitExceeded :: AllocationLimitExceeded
+ data AllocationLimitExceeded
+ displayException :: Exception e => e -> String
Prelude
+ (*>) :: Applicative f => f a -> f b -> f b
+ (<*) :: Applicative f => f a -> f b -> f a
+ (<*>) :: Applicative f => f (a -> b) -> f a -> f b
- all :: (a -> Bool) -> [a] -> Bool
+ all :: Foldable t => (a -> Bool) -> t a -> Bool
- and :: [Bool] -> Bool
+ and :: Foldable t => t Bool -> Bool
- any :: (a -> Bool) -> [a] -> Bool
+ any :: Foldable t => (a -> Bool) -> t a -> Bool
- class Monad m
+ class Applicative m => Monad m
+ class Monoid a
+ class Functor f => Applicative f
+ class Foldable t
+ class (Functor t, Foldable t) => Traversable t
- concat :: [[a]] -> [a]
+ concat :: Foldable t => t [a] -> [a]
- concatMap :: (a -> [b]) -> [a] -> [b]
+ concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
+ data Word :: *
- elem :: Eq a => a -> [a] -> Bool
+ elem :: (Foldable t, Eq a) => a -> t a -> Bool
+ foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
- foldl :: (b -> a -> b) -> b -> [a] -> b
+ foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
- foldl1 :: (a -> a -> a) -> [a] -> a
+ foldl1 :: Foldable t => (a -> a -> a) -> t a -> a
- foldr :: (a -> b -> b) -> b -> [a] -> b
+ foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
- foldr1 :: (a -> a -> a) -> [a] -> a
+ foldr1 :: Foldable t => (a -> a -> a) -> t a -> a
- length :: [a] -> Int
+ length :: Foldable t => t a -> Int
- mapM :: Monad m => (a -> m b) -> [a] -> m [b]
+ mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
- mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
+ mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
+ mappend :: Monoid a => a -> a -> a
- maximum :: Ord a => [a] -> a
+ maximum :: (Foldable t, Ord a) => t a -> a
+ mconcat :: Monoid a => [a] -> a
+ mempty :: Monoid a => a
- minimum :: Ord a => [a] -> a
+ minimum :: (Foldable t, Ord a) => t a -> a
- notElem :: Eq a => a -> [a] -> Bool
+ notElem :: (Foldable t, Eq a) => a -> t a -> Bool
- null :: [a] -> Bool
+ null :: Foldable t => t a -> Bool
- or :: [Bool] -> Bool
+ or :: Foldable t => t Bool -> Bool
- product :: Num a => [a] -> a
+ product :: (Foldable t, Num a) => t a -> a
+ pure :: Applicative f => a -> f a
- sequence :: Monad m => [m a] -> m [a]
+ sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
+ sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
- sequence_ :: Monad m => [m a] -> m ()
+ sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
- sum :: Num a => [a] -> a
+ sum :: (Foldable t, Num a) => t a -> a
+ traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
Data.Function
+ (&) :: a -> (a -> b) -> b
Control.Monad.Instances
- class Monad m
+ class Applicative m => Monad m
Data.Coerce
- coerce :: Coercible k a b => a -> b
+ coerce :: Coercible * a b => a -> b
Data.Version
+ makeVersion :: [Int] -> Version
Data.Complex
- cis :: RealFloat a => a -> Complex a
+ cis :: Floating a => a -> Complex a
- conjugate :: RealFloat a => Complex a -> Complex a
+ conjugate :: Num a => Complex a -> Complex a
- imagPart :: RealFloat a => Complex a -> a
+ imagPart :: Complex a -> a
- mkPolar :: RealFloat a => a -> a -> Complex a
+ mkPolar :: Floating a => a -> a -> Complex a
- realPart :: RealFloat a => Complex a -> a
+ realPart :: Complex a -> a
Data.Foldable
+ length :: Foldable t => t a -> Int
+ null :: Foldable t => t a -> Bool
System.Exit
+ die :: String -> IO a
Numeric.Natural
+ data Natural
Data.Bifunctor
+ bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
+ class Bifunctor p
+ first :: Bifunctor p => (a -> b) -> p a c -> p b c
+ second :: Bifunctor p => (b -> c) -> p a b -> p a c
Data.Functor.Identity
+ Identity :: a -> Identity a
+ newtype Identity a
+ runIdentity :: Identity a -> a
Data.Void
+ absurd :: Void -> a
+ data Void
+ vacuous :: Functor f => f Void -> f a
```

I’ve been watching the OPLSS 2014 lectures given by Ulf Norell on “Programming in Agda”. I *really* enjoyed his tutorial implementation of the simply typed lambda calculus, both as a demonstration of how to use Agda and as a primer on advanced techniques for achieving type safety guarantees for such an interpreter.

Here’s the link to OPLSS 2014.

Here’s a link to several tweets I made about it.

The Agda code given in the video no longer compiles. After some tinkering, I’ve managed to get it compiling with the latest Agda release. The source is available here for download, and is included below for web browsing. I’ve heavily annotated it to make it easier to understand for readers not familiar with emacs, Agda, or mathematical symbols.

The coolest thing about the context-management technique demonstrated below? It shows just how much can be proven with dependent types. Notice that there’s no need to use Either/Maybe to track semantic errors, because those errors are impossible by construction.

It necessarily means that the introduction rules (“constructors”) for all the terms are very demanding (e.g., when you parse a variable, you’re also forced to update the associated Context), but the end result is an evaluator that can’t go wrong.

Happy reading!

```
{-
Simply Typed Lambda Calculus in Agda
source:
- OPLSS 2014: Ulf Norell - Programming in Agda: Lecture 1
- https://www.cs.uoregon.edu/research/summerschool/summer14/curriculum.html
The following annotated tutorial assumes emacs>=24.3 and Agda>=2.4.2.3
Modifications from original:
* Tutorial used an older version of Agda that seemed to be less strict
about scoping and fixity declarations
* Made All (⊢ , []) instead of (∷ , [])
* Added infixr 3 _⊢_ for All type
* Avoids collisions with List definitions from Prelude
Keyboard notation: 'C-c C-n; eval env e <enter>' means:
* Hold Ctrl
* Press c
* Press n
* Release Ctrl
* Type 'eval env e'
* Press enter
C-c: Ctrl-c
M-c: Meta-c (meta is usually Alt, could be Esc or ...?)
- Quick test: 'M-x' should show 'M-x' at the bottom of your emacs window
Some useful commands (assuming emacs + agda 2.4.2.3):
* C-c C-l : type check whole buffer, replacing ? w/ goals { }0
* C-c C-c : [at goal] split case analysis on a variable
* C-c C-a : [at goal] try to auto solve a goal
* C-c C-n : evaluate expression typed in; sent to agda REPL
Some useful unicode inputs, thanks to agda2-mode:
* '\in' means: type '\' then 'i' then 'n'
|----------------+----------------+--------------------------------------------------+
| Input Sequence | Unicode Output | Description |
|----------------+----------------+--------------------------------------------------+
| \in | ∈ | Set membership |
| \:: | ∷ | Attach to left of list |
| \' | ′ | Prime, other |
| \-> | → | Function arrow; implication; implies |
| \forall | ∀ | For all... |
| \Gamma | Γ | A common variable to represent contexts |
| \|- | ⊢ | Entails; given thing on left, right must be true |
|----------------+----------------+--------------------------------------------------+
-}
module STLC where
-- import the special OPLSS Agda Prelude
-- download here: https://github.com/UlfNorell/agda-summer-school
-- follow these instructions:
-- - https://github.com/UlfNorell/agda-summer-school#getting-the-libraries
open import Prelude
-- Type C-c C-l now to make sure your environment is ready
-- All good? Nice!
--------------------------------------------------------------------------------
-- Simply Typed Lambda Calculus --
--------------------------------------------------------------------------------
-- The types for our lambda calculus
-- T := nat | bool
data Type : Set where
nat : Type
bool : Type
-- a type synonym
Cxt = List Type
-- Set membership
infix 3 _∈_
data _∈_ {A : Set} (x : A) : List A → Set where
zero : ∀ {xs} → x ∈ x ∷ xs
suc : ∀ {y xs} → x ∈ xs → x ∈ y ∷ xs
-- Lambda calculus terms
-- t := var | lit n | true | false | less | plus | if
-- Uses De Bruijn indexes for var scoping/lookup
data Expr (Γ : Cxt) : Type → Set where
var : ∀ {a} → a ∈ Γ → Expr Γ a
lit : {a : Type} (n : Nat) → Expr Γ nat
true : Expr Γ bool
false : Expr Γ bool
less : (a b : Expr Γ nat) → Expr Γ bool
plus : (a b : Expr Γ nat) → Expr Γ nat
if : {t : Type} (a : Expr Γ bool) (b c : Expr Γ t) → Expr Γ t
-- Mapping from Lambda Calculus types to Agda types
Value : Type → Set
Value nat = Nat
Value bool = Bool
-- Context assertions
infixr 3 _⊢_
data All {A : Set} (P : A → Set) : List A → Set where
[] : All P []
_⊢_ : ∀ {x xs} → P x → All P xs → All P (x ∷ xs)
-- Alternative context assertions
data Any {A : Set} (P : A → Set) : List A → Set where
zero : ∀ {x xs} → P x → Any P (x ∷ xs)
suc : ∀ {x xs} → Any P xs → Any P (x ∷ xs)
-- Alternative context membership
_∈′_ : {A : Set} (x : A) → List A → Set
x ∈′ xs = Any (λ y → x ≡ y) xs
-- making sure an environment is well-typed
lookup∈ : ∀ {A} {P : A → Set} {x xs} → All P xs → x ∈ xs → P x
-- impossible case, but needed to make Agda happy
lookup∈ [] ()
-- actual environment verification
lookup∈ (x ⊢ ps) zero = x
lookup∈ (_ ⊢ ps) (suc i) = lookup∈ ps i
-- Verify a context and convert it to an variable lookup Environment
Env : Cxt → Set
Env Γ = All Value Γ
-- evaluator for SLTC
eval : ∀ {Γ t} → Env Γ → (Expr Γ t) → Value t
eval env (var x) = lookup∈ env x
eval env (lit n) = n
eval env true = true
eval env false = false
eval env (less x y) = eval env x < eval env y
eval env (plus x y) = eval env x + eval env y
eval env (if p x y) = if eval env p then eval env x else eval env y
--------------------------------------------------------------------------------
-- Evaluator Demo --
--------------------------------------------------------------------------------
Γ : Cxt
Γ = nat ∷ bool ∷ []
env : Env Γ
env = 5 ⊢ false ⊢ []
-- to see output, type C-c C-l <enter> C-c C-n <enter> eval env e
-- [load buffer] [eval input]
-- Should see '9' below
e : Expr Γ nat
e = if (var (suc zero)) (var zero) (plus (lit 4) (var zero))
```

As a part of reading this paper (which is an excellent summary of intuitionistic logic and linear logic), I put together some notes in the form of an org mode file. I’m linking it here in case it’s of use to anyone else.

Notes: Link

Happy reading!

I’m interested in understanding linear logic better. I think it’s really powerful to give users of a programming language the option of handling segments of their programs as resources. I feel like linear logical constraints (LLC) as a first class citizen of a language would lead to:

- Better error messages when those constraints aren’t satisfied
- General availability of these tools for the development of programs
- A run-time system that can optimize segments of the program involving LLC

What do I mean by resources? Things like:

- Memory
- Files
- Sockets
- Streams
*Sessions*- Transactions
- Locking Primitives

There’s a lot to unpack in the literature of linear logic. A good starting point from the programming point of view is to see what the Rust programming language has done, or nearly any paper on session types.

I use a type-signature-like notation for logical rules to make them easier to translate to this textual medium. For example:

```
Γ ⊢ A Δ ⊢ B
------------ (×-I)
Γ,Δ ⊢ A × B
```

Becomes:

```
×-I : ⟦(Γ ⊢ A) (Δ ⊢ B)⟧
⟶ ⟦(Γ, Δ ⊢ A × B)⟧
```

The name now comes first, rather than being off to the side. The required assumtions start the type signature, and the conclusion becomes the “return” of the type. It’s a take on propositions-as-types for the sake of facilitating my note taking.

]]>