Small changes to XMonad like changing keyboard shortcuts require little Haskell knowledge. However, bigger customizations, especially to organize your code when adapting other people’s configurations, are easier when you understand Haskell functions.

### Function notation

Briefly, a function maps a thing to another thing. It takes in a thing as input and produces another thing as output.

You surely know the following function notation from math class in high school:

``f(x) = x + 1``

Here, `f` is the function name, `x` is a variable, a placeholder that you can plug values into, and `x + 1` tells you how to compute the result. Your teacher may have told you that you were allowed to plug in a real number for `x` into `f` and got a real number as a result.

However, mathematicians normally leave no doubt about what is allowed to go in and what can come out. They use a slightly improved notation that you may not have used in school. It includes “the type of this function”.

``````Math:
f : ℤ -> ℤ   -- math "type signature"/declaration
f(x) = x + 1 -- function body/definition``````

In math you write a “type signature” for a function using a single colon `:`. The whole line

``f : ℤ -> ℤ   -- math "type signature"/declaration``

is the signature of `f`, which tells you that the type of `f` is:

``ℤ -> ℤ``

Briefly, a type is the name for a collection of values. For example, ℤ is the name for the collection of integer numbers, and ℤ -> ℤ is the name for the collection of all possible functions that accept an integer as input and return an integer as output. From this notation it is obvious that our function `f` only allows us plug in an integer and computes an integer as a result.

Once we have defined a function `f`, we can use/apply it as follows:

``f(3)         -- function usage/application, result=4``

You write the name `f` followed by your value `3` inside parentheses `(...)` and the expression `f(3)` represents the resulting number `4`.

Haskell is hugely inspired by math, so it’s no wonder that its notation for functions is quite similar to math. You would write the same function `f` in Haskell as follows:

``````-- Haskell:
f :: Int -> Int -- haskell type signature/declaration
f x = x + 1     -- function body/definition

f 3             -- function usage/application, result=4``````

The minor differences between Haskell and math are: You use a double colon `::` instead of a single colon in the type signature, you write `Int` for the integer numbers and you leave out the parentheses `(...)` when you define or use a function. Instead you just separate the function name `f` from the variable `x` or a value `3` with a single space like `f x`. Again the expression `f 3` represents the resulting number `4`.

In Haskell the type signature notation using `::` is also extended and used for constants. For example, in XMonad you write

``````myTerminalApp :: String
myTerminalApp = "gnome-terminal"

myWorkspaces :: [String]
myWorkspaces = ["1","2","3"]``````

for the terminal setting and workspace setting. The type signatures tell you precisely that `myTerminalApp` is a string and `myWorkspaces` a list of strings.

However, one huge benefit of Haskell is that you often don’t need to write type signatures. Type signatures always exist, but Haskell can generate them automatically in many situations. In many XMonad example configurations you won’t find many (if any) type signatures:

``````myTerminalApp = "gnome-terminal"

myWorkspaces = ["1","2","3"]``````

It is very obvious that `myTerminalApp` is a string and `myWorkspaces` is a list of strings, so Haskell will generate the type signature automatically. You can leave a type signature out, when the type is obvious to you (and Haskell).

Another place in XMonad where you wouldn’t write a type signature is the keymaps setting:

``````import qualified Data.Map as M

-- myKeysFunc :: XConfig Layout -> M.Map (ButtonMask,KeySym) (X ())
myKeysFunc baseConfig = M.fromList \$
[ ((mod4Mask, xK_Return), spawn \$ terminal baseConfig)
]
-- myConfig :: XConfig (ModifiedLayout.... )
myConfig = def
{ keys = myKeysFun -- override previous keymaps
}``````

The type signatures of `myKeysFunc` and `myConfig` are very long, difficult to write and difficult to read. It is not useful to write them yourself, because Haskell will generate these signatures automatically. For example, Haskell knows that `def` is a value of type `XConfig` and that you only modify a single setting of it with the `{ .. }` record notation. It will therefore conclude and know that `myConfig` must also the a value of type `XConfig`.

Benefits of writing type signatures in Haskell

Just as the type `Int` is a collection of integer numbers and type `Char` is a collection of single letters, digits (and other symbols) so is `Int -> Int` a collection of all possible functions from `Int` to `Int` (You can read the arrow `->` as “to”). And just as `'a'` is a value of this collection `Char` and therefore has type `Char`, this specific function `f` is a value of the collection `Int -> Int` and therefore has type `Int -> Int` ( we say `f` has type “`Int` to `Int`).

A type signature of a function serves two purposes: First, it tells you a lot about what a function does without looking into or caring about the function body/definition, thus, without knowing how it does it.

``toUpper :: Char -> Char``

For example, the signature for the built-in Haskell function `toUpper` tells you that it takes in a value of type `Char` and produces another value of type `Char`. Together with its name you can guess what it does: It turns a lowercase letter like `'a'` into an uppercase letter like `'A'`. But you don’t know or care how it does it.

Second, a type signature allows the Haskell type checker to cross-check your code. For example in the following code

``````myTerminalApp :: String
myTerminalApp = 3 -- error, no type match``````
the type checker will conclude (using the function body alone) that `myTerminalApp` must be an integer. The checker will compare this computed type to the type you have written in your type signature. And because these don’t match, the checker will give you an error.
Importing Modules with `import`

Haskell programmers separate all their code into “modules”, Roughly, a module is a single Haskell file. With `import` statements you can make functions of other modules available and usable in your current file/module. For example, you can make the XMonad functions and values like `xmonad` and `def` available in your configuration file with

``import XMonad``

There are several styles to import a module. We will use the `noBorders` and `smartBorders` functions from `XMonad.Layout.NoBorders` module (to remove borders around your windows), and the `fromList` function from the `Data.Map` module (to create keyboard shortcuts for the keys setting) as our examples.

The most basic style is to import modules as a whole:

``````import Data.Map

You write these lines at the top of your configuration file to import all functions in that module. However, as your configuration file gets bigger, the number of your imported modules will grow large. So when you see `fromList` in your code some months later, you may have forgotten which module this function came from. To avoid this you should use one of the following two styles of import:

First, you can list the imported functions and values explicitly.

``````import Data.Map (fromList)

Here you will only make the `fromList`, `noBorders` and `smartBorders` functions available. Only use the explicit import if you only need one or up to four functions/values, otherwise this list will get too long.

Second, you can use a “qualified import” to make all functions from a module available but with a prefix that tells you which module a functions comes from:

``````import qualified Data.Map as M

Here in your code you will have to write `M.fromList` with the `M.` prefix (as in keys setting type example) and `N.noBorders` and `N.smartBorders` with the `N.` prefix. With these prefixes you will always know which module these functions come from. Use this style of import when you need to import five or more functions from a less frequently used or known module. Don’t use this style of import for well-known or popular modules like `XMonad`; you always import well-known modules normally:

``import XMonad``

You and many other people who may read your configuration will know with time which functions come come from the `XMonad` module.

Actually, there are even more styles. If you are interested, you can read about all the styles to import modules.

Dollar operator `\$`

Roughly, the dollar operator separates code on its left from code on its right. This function is used to reduce the number of parentheses to make your configuration easier to read. For example, you may have the following function:

``````addOne :: Int -> Int -- haskell type signature/declaration
addOne x = x + 1     -- function body/definition``````

You can use and apply it as follows:

``addOne (addOne 1)``

This expression is valid, because first you compute `addOne 1` and the result `2` is given to the other `addOne`. Here you have to write parentheses, because leaving them out as in

``addOne addOne 1``

will be interpreted by Haskell as the invalid expression:

``(addOne addOne) 1``

This expression will result in an error, because `addOne` only accepts integer values like `1` but not a function value like `addOne`. So you can either use parentheses or you can use the `\$` operator as follows:

``addOne \$ addOne 1``

It will separate its left side from its right side and be interpreted as:

``(addOne) (addOne 1) -- the left `(addOne)` is simply `addOne```

The benefit of using `\$` in this example is small, but it is huge when your code is already inside many parentheses. For example, for the XMonad keys setting you often see a lot of parentheses:

``````myKeysFunc baseConfig = M.fromList (
[ ((mod4Mask, xK_Return),          spawn (terminal baseConfig))
])``````

Here the `spawn` function accepts the name an app as a string value, which is extracted first from `baseConfig` with the `terminal` accessor function using parentheses.
[Accessor functions.]
Similarly, the `windows` function accepts a single window operation value, which is constructed using `shift "1"` inside parentheses. Also the `M.fromList` function accepts a single list, which is wrapped in parentheses. You can make this code a lot easier to read by using `\$` as follows:

``````myKeysFunc baseConfig = M.fromList \$
[ ((mod4Mask, xK_Return),          spawn \$ terminal baseConfig)
]``````

Again, the dollar function separates code on its left from code on its right but only inside parentheses. For example, this is why the `\$` operator to the right of the `spawn` function only separates `(spawn) (terminal baseConfig)`, but does not separate all the code from the left and above it from all the code on the right and below it.

Dot operator `.`

It “composes” two functions and is written in the form:

``<second function> . <first function>``

When we say “compose” we mean that it combines two functions to create a new function just like the `+` operator combines two numbers to create a new number. This new function applies the first function, takes its result and passes it to the second function. You can compose any two functions where the output of the first one can be plugged into the second one.

In the following contrived example we have two functions:

``````addOne x = x + 1

square x = x * x

We compose them with the dot operator and apply the resulting function to `2` as follows:

``````(square . addOne) 2
composedFunc 2``````

These two functions are composable because the output of `addOne` is a number that we can plug into `square`. The resulting functions `(square . addOne)` and `composedFunc` (both are the same) are applied to `2` and compute:

``square (addOne 2)``

That is, they first add one to `2`, and then square the result `3` to `9`.

If you compose more than two functions, the dot operator composes from right to left. So

``(third . second . first) 2``

computes

``third (second (first 2) )``

In XMonad this dot operator becomes handy to set the keys setting as follows:

``````import qualified Data.Map as M

-- myKeys :: XConfig ... -> M.Map ...
myKeys baseConfig@(XConfig {modMask = modKey}) =
[ ((modKey, xK_f), spawn "firefox"))
, ((modKey .|. shiftMask, xK_1), windows (shift "1"))
-- ...
]

myConfig = def
{ keys = M.fromList . myKeys-- override previous keymaps
}``````

This `M.fromList . myKeys` thing is a new function that expects an `XConfig` value and constructs a Haskell “Map” of keymaps: precisely what `keys` has to be. This works because we first apply `myKeys`, which expects an `XConfig` value and computes a list of keymaps, and then pass the resulting list to `M.fromList`, which as its name suggests expects a list of keymaps and produces a “Map” of keymaps.

Lists

Lists are used throughout XMonad and are easy to recognize and to write. You create lists in Haskell with square brackets.

``list1 = ["1","2","3"]``

You can also write each element on a new line:

``````list2 =
[ 1
, 2
, 3
, 4
, 5
]``````

Just make sure that the lines are indented. This style is easier to read when the elements are long to write.

All the elements in that list must be of the same type. For some types like integer numbers there is a range notation with `..`. For example, you can use this notation on integers and XMonad keyboard key representation numbers.

``````list3 = [1..5] -- result=[1,2,3,4,5]
list4 = [xK_1..xK_5] -- result=[xK_1,xK_2,xK_3,xK_4,xK_5]``````

You can combine two lists with the `++` operator:

``list5 = [1,2] ++ [3,4] -- result=[1,2,3,4]``

This `++` operator is often used in the keymaps section of your XMonad configuration file to give your (possibly long) list of keymaps a little bit more structure.

``````myKeys =
-- Change XMonad built-in key combinations
[ ("M-S-1", windows (shift "1:work") )
-- ...
]
++
[ ("M-f", spawn "firefox")
-- ...
]``````

A notation called list comprehension can be used to construct a new list out of combinations of elements of existing lists. The notation in Haskell is as follows:

``[ <do something with values> | <value1> <- <somelist1>, <value2> <- <somelist2>]``

A concrete example is

``myPairs = [ (number, name) | number <- [1,2], name <- ["John", "Alice"]``

which constructs a list called `myPairs` that contains all combinations of those numbers and names:

``[(1,"John"), (2,"John"), (1,"Alice"), (2,"Alice")]``

You can also go through a list of pairs like

``[ number | (number, name) <- myPairs]``

for example to collect only the numbers of `myPairs`:

``[1,2,1,2]``

In XMonad “list comprehension” is used and needed when you change the names of workspaces, because you will have to modify a lot of workspace keymaps. You will often see something like this:

``````[ ("M-" ++ otherModKey ++ [key], windows \$ action workspaceID)
| (key, workspaceID)  <-   [("1","1:work"), ("2","2:browser")]
, (otherModKey, action) <- [("", view), ("S-", shift)]
]``````

See if you can understand why this is the same as:

`````` [ ("M-1", windows \$ view "1:work")
, ("M-2", windows \$ view "2:browser")
, ("M-S-1", windows \$ shift "1:work")
, ("M-S-2", windows \$ shift "2:browser")
]``````
`zip` function

You often see the `zip` function in XMonad when you modify the keymaps for your workspaces. It combines two lists of single elements into a single list of paired elements. For example

``zip [1,2,3] ["one","two","three"]``

computes the list of pairs:

``[(1,"one"), (2,"two"), (3,"three")]``

The first element of the first list is paired with the first element of the second list, and so on.

In XMonad you will often see code like

``zip (workspaces baseConfig) [xK_1 .. xK_9]``

which is the same as:

``````workspaceNames = ["1","2","3"]
xkeys = [xK_1, x_K_2, xK_3]

zip workspaceNames xkeys``````

and computes the following list:

``[("1",xK_1), ("2",xK_2), ("3",xK_3)]``

Take a look at its documention page.

Infix notation ``...``

If you surround a function that takes precisely two arguments with backticks ``...``, you can use it “infix”. That is, you can use it inbetween two values.

For example, a function like

``````plus :: Int -> Int -> Int
plus x y = x+y``````

is normally used in Haskell as follows:

``plus 1 2 -- result=3``

If you write `plus` using the infix notation you can use the `plus` function more readably as follows:

``1 `plus` 2 -- result=3``

In XMonad configurations you will often encounter this notation with the `additionalKeysP` function when setting up keymaps with the EZ notation.

``````myKeys =
[ ("M-S-1", windows (shift "1") )
, ("M-f", spawn "firefox")
-- ...
]
myConfig = def
{ -- other settings

Here, `additionalKeysP` is written infix with backticks rather than following, regular but harder to read style:

``````myConfig = additionalKeysP (def
{ -- other settings
}) myKeys``````

#### Malte Neuss

Java Software Engineer by day, Haskell enthusiast by night.

## Other Posts In Series

Small changes to XMonad like changing keyboard shortcuts require little Haskell knowledge. However, bigger customizations, especially adapting other people’s configurations, are easier when you understand Haskell types and records.

#### Configure a light-weight status bar for XMonad: Xmobar

The status bar Xmobar works out of the box on the top edge of your screen and shows useful system info. However, if you want to make it look nice and change what information to show, you can customize it with a tiny bit of Haskell.