# K&R Challenge 3 and 4: Functional Temperature Conversion

The other day, I implemented the C solution to exercises 3 and 4 in *The C Programming Language*, today I’ll be implementing the Haskell solution. As a reminder, the requirements are:

Modify the temperature conversion program to print a heading above the table

… and …

Write a program to print the corresponding Celsius to Fahrenheit table.

I could take the easy way out, and implement the Haskell solution almost identically to the C solution, replacing the `for`

loop with a call to `map`

, but that’s neither interesting to do, nor is it interesting to read about. I’ll be taking this problem to the next level.

## Requirements

For my temperature program, I’d like it to be able to convert between any arbitrary temperature unit. For the purposes of this post, I will be implementing Celsius, Fahrenheit, Kelvin (equivalent to Celsius, except 0 degrees is absolute zero, not the freezing point of water), and Rankine (the Fahrenheit version of Kelvin).

That said, nothing about my solution should rely on the fact that these four temperature scales are being implemented. A programmer should be able to implement a new temperature unit with minimal changes to the program. Ideally, just by implementing a new type.

Additionally, given a bunch of conversions, the program should be able to output a pretty table showing any number of temperature types and indicating what converts to what.

## First, Conversion

This problem is clearly broken up into two sub-problems: conversion, and the table. First, we need to handle conversion. This being Haskell, the right answer is likely to start by defining some types. Let’s create types for our units:

```
newtype Celsius = Celsius Double deriving (Show)
newtype Fahrenheit = Fahrenheit Double deriving (Show)
newtype Kelvin = Kelvin Double deriving (Show)
newtype Rankine = Rankine Double deriving (Show)
```

I’ve chosen to make a type for each unit, and since they only contain one constructor with one field, I use a `newtype`

instead of a `data`

. Now, how to convert these? A straightforward solution to this would be to define functions that convert each type to each other type. Functions that look like:

```
celsiusToFahrenheit :: Celsius -> Fahrenheit
celsiusToKelvin :: Celsius -> Kelvin
...
rankineToKelvin :: Rankine -> Kelvin
rankineToCelsius :: Rankine -> Celsius
```

A diagram for these conversions looks like this:

That’s a lot of conversions! One might argue that it’s manageable, but it certainly doesn’t meet requirement #1 that implementing a new unit would require minimal work; to implement a new conversion, you’d need to define many conversion functions as well! There must be a better way.

Let’s think back to chemistry class. You’re tasked with converting litres to hours or somesuch. Did you do that in one operation? No, you used a bunch of intermediate conversion to get to what you needed. If you know that X litres are Y dollars, and Z dollars is one 1 hour, then you know how many litres are in 1 hour! These are called conversion factors.

Luckily for us, our conversions are much simpler. For any temperature unit, if we can convert it to and from celsius, then we can convert it to and from any other unit! Let’s define a typeclass for `Temperature`

:

```
class Temperature a where
toCelsius :: a ->
Celsius
fromCelsius :: Celsius ->
a
value :: a ->
Double
scaleName :: a ->
String
convert :: (Temperature b) =>
a ->
b
convert f = fromCelsius $ toCelsius f
```

Our `Temperature`

typeclass has five functions: functions to convert to and from celsius, a function to get the value from a unit, a function to get the name of a unit, and a final function `convert`

. This final function has a default implementation that converts a unit to celsius, then from celsius. Using the type inferrer, this will convert any unit to any other unit!

```
convert Rankine 811 :: Kelvin
convert Celsius 123 :: Fahrenheit
convert Kelvin 10000 :: RelativeToHeck
```

Now to implement a new temperature, you only need to implement four functions, as `convert`

is a sane solution for all cases. This arrangement gives us a conversion diagram that looks like:

Much better. Let’s go through our `Temperature`

implementations for our types:

```
instance Temperature Celsius where
toCelsius c = c
fromCelsius c = c
value (Celsius c) = c
scaleName _ = "Celsius"
```

Of course `Celsius`

itself has to implement `Temperature`

. It’s implementation is trivial though; no work needs to be done.

```
instance Temperature Fahrenheit where
toCelsius (Fahrenheit f) = Celsius ((5 / 9) * (f - 32))
fromCelsius (Celsius c) = Fahrenheit ((9 / 5) * c + 32)
value (Fahrenheit f) = f
scaleName _ = "Fahrenheit"
```

Now things are heating up. The conversion functions are identical to the C implementation.

```
instance Temperature Kelvin where
toCelsius (Kelvin k) = Celsius (k - 273.15)
fromCelsius (Celsius c) = Kelvin (c + 273.15)
value (Kelvin k) = k
scaleName _ = "Kelvin"
```

The `Kelvin`

implementation looks much like the `Fahrenheit`

one.

```
instance Temperature Rankine where
toCelsius (Rankine r) = toCelsius $ Fahrenheit (r - 459.67)
fromCelsius c = Rankine $ 459.67 + value (fromCelsius c :: Fahrenheit)
value (Rankine r) = r
scaleName _ = "Rankine"
```

The conversion between Fahrenheit and Rankine is much simpler than the conversion between Celsius and Rankine; therefore I will do just that. After converting to and from Fahrenheit, it’s a simple matter of calling `toCelsius`

and `fromCelsius`

.

## Bringing The Monads

Now that the easy part is done, we get to create the table. Our table should have as many columns as it needs to display an arbitrary number of conversions. To that end, let’s define a data structure or two:

```
data ConversionTable = ConversionTable [String]
[[TableRowElem]] deriving (Show)
data TableRowElem = From Double | To Double
| NullConv Double
| Empty deriving (Show)
```

The `ConverstionTable`

, like the name suggests, is our table. The list of strings is the header, and the list of lists of `TableRowElem`

are our conversions. Why not just have a list of `Double`

? We need to have our cells contain information on what they mean.

To that end, I created a `TableRowElem`

type. `From`

is an original value, `To`

is a converted value, `NullConv`

represents the case were we convert from some type to the same type, and `Empty`

is an empty cell. The problem of how to place elements into this data structure still remains however. To solve that, things are going to get a bit monadic. Let’s define some intermediate builder types:

```
type Conversion a b = (a, b)
toConversion :: (Temperature a, Temperature b) =>
a ->
(a, b)
toConversion a = (a, convert a)
```

First we have `Conversion`

, and the corresponding `toConversion`

function. This simply takes a unit, and places it in a tuple with its corresponding conversion. Next, we have the `TableBuilder`

:

```
type TableBuilder a = WriterT [[TableRowElem]]
(State [String]) a
```

Here we have a `WriterT`

stacked on top of a `State`

monad. The writer transformer contains the list of table rows, and the state monad contains the header. The idea is that as rows are “logged” into the writer, the header is checked to make sure no new units were introduced. To this end, if only two units are introduced, the table will have two columns. If 100 units are used, then the table will have 100 columns.

**NOTE:** I realize that `WriterT`

and `State`

are not in the standard library. I only promised to limit the usage of libraries for Haskell solutions. This means avoiding the use of things like Parsec or Happstack. Frameworks and libraries that vastly simplify some problem or change the way you approach it. To this end, if I feel a monad transformer or anything along these lines are appropriate to a problem, I will use them. I’ll try to point out when I do though. Besides, I could have just re-implemented these things, but in the interest of not being a bad person and re-inventing the wheel, I’ve decided to use a wheel off the shelf.

So, how do we use this `TableBuilder`

? I’ve defined a function for use with this monad:

```
insertConv :: (Temperature a, Temperature b) =>
Conversion a b ->
TableBuilder ()
insertConv (a, b) =
do oldHeader <- lift $ get
workingHeader <- ensureElem a oldHeader
finalHeader <- ensureElem b workingHeader
lift $ put finalHeader
tell [buildRow a b finalHeader []]
where ensureElem a h = return $ case ((scaleName a) `elem` h)
of True -> h
False -> h ++ [(scaleName a)]
buildRow _ _ [] r = r
buildRow a b (h:xs) r
| (scaleName a) == (scaleName b) && (scaleName a) == h = r ++ [NullConv $ value a]
| (scaleName a) == h = buildRow a b xs (r ++ [From $ value a])
| (scaleName b) == h = buildRow a b xs (r ++ [To $ value b])
| otherwise = buildRow a b xs (r ++ [Empty])
```

Yeah, that one is kind of a doosey. Let me walk you through it. This function takes a `Conversion`

, and returns a `TableBuilder`

.

In the first four lines of the `do`

block, we update the header. We `lift`

the `State`

monad, then `get`

we call `ensureElem`

with the first and second units, then we `put`

the new updated header back into the `State`

monad.

The `ensureElem`

function checks the header list to see if the current unit is a member. If it is, the header list is returned unchanged, if it’s not the unit is appended to the end and the new list is returned. In this way, whenever a conversion is added to the table, the header is updated.

After updating the header, we call `tell`

with the result of `buildRow`

, “writing” the row into the `Writer`

monad. The `buildRow`

function recursively adds `TableRowElem`

s to the result list depending on the current heading. In this way, conversions are placed in the appropriate column.

In addition to that function, I’ve defined a function to simplify working with the `TableBuilder`

:

```
buildTable :: TableBuilder a ->
ConversionTable
buildTable b = let result = runState (runWriterT b) []
in ConversionTable (snd result)
(snd $ fst result)
```

Working with some of these `MTL`

monads can be confusing for people coming from imperative backgrounds. I’ve been working with Haskell for almost a year now and I still get extremely confused by them. It can take some muddling through haddoc pages to work them out, but the good news is that you mainly just need to define one function that takes a monad (in the form of a `do`

block), and returns a whatever. The `buildTable`

function takes a `TableBuilder`

, and returns a `ConversionTable`

. It handles calls to `runState`

and `runWriterT`

, and then unwraps the resulting tuple and builds the `ConversionTable`

.

This function can be called like this:

```
buildTable $ do insertConv someConversion
insertConv someOtherConversion
```

… and so on. The only thing to remember is that the final value of `a`

for the `do`

block must be `()`

. Conveniently, `insertConv`

return a value of type `TableBuilder ()`

, so if the last call is to this function, then you are good. You can also always end it with `return ()`

if you like.

## Pretty Printing

Finally, we have the matter of printing a nice pretty table. For that, we need yet another function:

```
prettyPrint :: ConversionTable ->
String
prettyPrint (ConversionTable h r) = let widestCol = last $ sort $ map length h
columnCount = length h
doubleCell = printf ("%-" ++ (show widestCol) ++ ".1f")
stringCell = printf ("| %-" ++ (show widestCol) ++ "s |")
emptyCell = replicate widestCol ' '
horizontalR = (replicate (((widestCol + 4) * columnCount) + 2) '-') ++ "\n"
formatRow row = "|" ++ (concat $ map formatCell row) ++ "|\n"
formatCell (From from) = "| " ++ (doubleCell from) ++ " |"
formatCell (To to) = "> " ++ (doubleCell to) ++ " |"
formatCell Empty = "| " ++ emptyCell ++ " |"
formatCell (NullConv nc) = "| " ++ (doubleCell nc) ++ " |"
in horizontalR
++ ("|" ++(concat $ map stringCell h) ++ "|\n")
++ horizontalR
++ (concat $ map formatRow (normalizeRowLen (columnCount) r))
++ horizontalR
where normalizeRowLen len rows = map (nRL' len) rows
where nRL' len' row
| (length row) < len' = nRL' len' (row ++ [Empty])
| otherwise = row
```

Yeah… Sometimes the littlest things take the most work. You’d think all this plumbing we’ve been doing would be the most complecated bit, but you’d be wrong. Let’s try to make sense of this mess function by function:

`widestCol = last $ sort $ map length h`

This function determines the widest column based on the header. Typically, this is going to be “Fahrenheit”, but it doesn’t have to be. It should be noted that if a data cell is wider than this, then the pretty printer will mess up. Like most things in life, there is room for improvement here. That said, unless you’re converting the temperature of the core of the sun, you probably won’t have an issue here.

`columnCount = length h`

Returns the number of columns in the table. Used by the horizontal rule function.

`doubleCell = printf ("%-" ++ (show widestCol) ++ ".1f")`

Ahh, our old friend `printf`

. It exists in Haskell and works in much the same way as it did in C. The `doubleCell`

function converts a temperature value to a string, left aligns it, pads it by `widestCol`

, and has it show one decimal place.

`stringCell = printf ("| %-" ++ (show widestCol) ++ "s |")`

Much like with `doubleCell`

, this function pads, and left-aligns a string. This is used by the header.

`emptyCell = replicate widestCol ' '`

This one is pretty self-explanatory. It prints an empty cell of the appropriate width.

`horizontalR = (replicate (((widestCol + 4) * columnCount) + 2) '-') ++ "\n"`

This function prints a horizontal rule. This will be a solid line of “-” across the width of the table.

`formatRow row = "|" ++ (concat $ map formatCell row) ++ "|\n"`

This function formats a table data row. It maps `formatCell`

over the list of cells, flattens it, then adds a pretty border around it.

```
formatCell (From from) = "| " ++ (doubleCell from) ++ " |"
formatCell (To to) = "> " ++ (doubleCell to) ++ " |"
formatCell Empty = "| " ++ emptyCell ++ " |"
formatCell (NullConv nc) = "| " ++ (doubleCell nc) ++ " |"
```

In this function, much of the work is done. It formats the cell using `doubleCell`

or `emptyCell`

, the applies a border to the cell. It denotes a cell containing a `To`

by adding a `>`

on the left.

Now that we’ve covered the `let`

-bound functions, let’s talk about the actual function body:

```
horizontalR
concat $ map stringCell h) ++ "|\n")
horizontalR
concat $ map formatRow (normalizeRowLen (columnCount) r))
horizontalR
```

This bit is prett straightforward. First, it prints a horizontal line. Second, it maps `stringCell`

over the header list, flattens it, and gives it a border. Third it prints another horizontal line. Fourth is maps `formatRow`

over the normalized row list, then flattens it. Finally, one last horizontal line. After this is all said and done, it concats it all together.

You may be wondering about that `normalizeRowLen`

function. If you were paying particularly close attention to the `insertConv`

function, you may have noticed an issue. Let’s walk through it in ghci:

```
*Main> let fc = toConversion (Fahrenheit 100) :: (Fahrenheit, Celsius)
*Main> buildTable $ do insertConv fc
ConversionTable ["Fahrenheit","Celsius"] [[From 100.0,To 37.77777777777778]]
```

We add one conversion, we get two columns. Everything seems to be in order here, but let’s add another conversion and see what happens:

```
*Main> let fc = toConversion (Fahrenheit 100) :: (Fahrenheit, Celsius)
*Main> let cr = toConversion (Celsius 100) :: (Celsius, Rankine)
*Main> buildTable $ do {insertConv fc; insertConv cr;}
ConversionTable ["Fahrenheit","Celsius","Rankine"] [[From 100.0,To 37.77777777777778],[Empty,From 100.0,To 671.6700000000001]]
```

See the problem? Let’s add some newlines to make it clearer:

```
ConversionTable ["Fahrenheit","Celsius","Rankine"]
[[From 100.0,To 37.77777777777778],
[Empty,From 100.0,To 671.6700000000001]]
```

As we add more columns, the rows with less columns are never updated to have the new column count. Logically, this is fine, since the extra entries would just be `Empty`

anyways, but our pretty printer would print this table like so:

```
--------------------------------------------
|| Fahrenheit || Celsius || Rankine ||
--------------------------------------------
|| 100.0 |> 37.8 ||
|| || 100.0 |> 671.7 ||
--------------------------------------------
```

As you add more and more columns, the problem gets worse and worse. Enter our `normalizeRowLen`

function:

```
normalizeRowLen len rows = map (nRL' len) rows
where nRL' len' row
| (length row) < len' = nRL' len' (row ++ [Empty])
| otherwise = row
```

This is another fairly straightforward function. If the row has the same number of columns as the header, it is returned unchanged. If it doesn’t, `Empty`

is added to the end until it does.

With that, our program is complete. Let’s try it out:

```
main = do k <- return (toConversion $ Kelvin 100 :: (Kelvin, Rankine))
f <- return (toConversion $ Fahrenheit 451 :: (Fahrenheit, Kelvin))
r <- return (toConversion $ Rankine 234 :: (Rankine, Celsius))
c <- return (toConversion $ Celsius 9 :: (Celsius, Fahrenheit))
nc <- return (toConversion $ Rankine 123 :: (Rankine, Rankine))
putStrLn $ prettyPrint $ buildTable $ do insertConv k
insertConv f
insertConv r
insertConv c
insertConv nc
```

In our `main`

, we create a bunch of conversions. Then we `prettyPrint`

them and `putStrLn`

the result. The following will be printed to the console:

```
----------------------------------------------------------
|| Kelvin || Rankine || Fahrenheit || Celsius ||
----------------------------------------------------------
|| 100.0 |> 180.0 || || ||
|> 505.9 || || 451.0 || ||
|| || 234.0 || |> -143.2 ||
|| || |> 48.2 || 9.0 ||
|| || 123.0 || || ||
----------------------------------------------------------
```

Any type that implements `Temperature`

can be put into a table this way. To add a new unit to the program, it’s as easy as implementing four one-line functions!

# “Haskell Doesn’t Have Loops”

Among the first thing any prospective Haskeller learns is that “Haskell doesn’t have loops.” You know what I say to that?

Challenge Accepted.

While it’s true that loops are not a primitive control structure in Haskell like they are in imperative languages, that doesn’t mean we can’t add them. But what should a loop look like? In C, a `while`

loop looks like this:

```
while (some_predicate() != TRUE)
{
do_stuff();
}
```

It’s basically the same in any C-like language; first, you type the type of loop (`while`

, in this case), then you type some predicate that evaluates to a boolean value, then on the next line, an arbitrary block of code.

I feel that it would be in poor taste to just define a function `while`

that takes another function that represents the block of code to execute. It feels out of line with the spirit of the problem. Luckily for us, Haskell’s `do`

notation has a very “arbitrary block of code” feel to it. But that requires us to use a monad…

Which brings us to the root of the issue: what exactly do we *do* in loops? Basically, while the predicate is false, we mutate some state, then test the predicate again. If the predicate is still false, we mutate some more state until it evaluates true. The key word there is state.

Take a look at my sample loop above. The loop calls two functions: `some_predicate`

, and `do_stuff()`

. Neither function takes any arguments. If this were Haskell, then we’d have a problem, because the loop would never exit. If a function always returns the same result given the same input, then a function with no input will always only return one thing. `some_predicate`

would always either return `True`

(resulting the the loop not being entered), or `False`

, resulting in an infinite loop. However, in C this loop probably works fine. This is because C has state.

To this end, my Haskell loop must operate on a `State`

monad. Now, with this out of the way, let’s jump to the implementation!

## The Implementation

So, how would we implement a loop in Haskell? I think a good source of inspiration here is the `Monad`

typeclass. Monads have a very “language-feature” feeling to them, but they are not primitives. Monads are a typeclass, some functions, and some data types. Similarly, I’ve created a `Loop`

typeclass:

```
class Loop a where
exec :: a -> a
```

The `Loop`

typeclass is very simple. It defines one function, `exec`

that takes a loop, and returns another loop of the same type. Different types of loops behave differently, so it’s up to the implementor to determine how the loop should function. For this example, I’ve implemented the `while`

loop. Here is my `While`

type:

```
data While a = While {whilePred :: (a -> Bool),
whileState :: a,
whileBody :: State a ()}
```

My `While`

type has three fields. The whileState field is a state value for use by the loop’s state monad. The whileBody field is the `State`

monad itself. Finally the whilePred field is a predicate function that is used to determine if the loop should terminate.

Next, we have an implementation for class `Loop`

:

```
instance Loop (While a) where
exec w = let predicate = (whilePred w) (whileState w)
s' = execState (whileBody w) (whileState w)
w' = While {whileState = s',
whilePred = (whilePred w),
whileBody = (whileBody w)}
in case (predicate) of True -> w
False -> exec w'
```

It’s a little verbose, but it’s not too bad when you break it down. The meat of the function is in the `case`

statement: we test the predicate, by calling `whilePred`

on `whileState`

. If the predicate returns `True`

, we return the current `While`

object. If it evaluates `False`

, we iterate once by calling `execState`

using `whileState`

as the initial state, and `whileBody`

as the State monad. When that’s done, we construct a new `While`

object with the old `State`

monad, old predicate function, and new state, and then recursively call `exec`

. This continues until the predicate evaluates `True`

. Like any good while loop, this could potentially go on forever.

So, where does that leave us? We have a while loop type, and a function to “run” the loop. So, as it stands, we have to build the `While`

, then call `exec`

on the `While`

, then finally call `whileState`

on the `While`

to get the result. Doesn’t really feel like a C-like `while`

loop, does it? Well, we’re not done yet. Let’s define one last function:

```
while :: a -> (a -> Bool) -> (State a ()) -> a
while s p b = whileState $
exec (While {whileState = s,
whilePred = p,
whileBody = b})
```

This function is where the magic happens. This function approximates the `while`

statement from C. By calling this function, we can perform a “while loop” that looks like so:

```
while initialState
predicateFunction
$ do oldState <- get
newState <- mutate oldState
put newState
```

The `while`

function will return the final mutation of `initialState`

. Here’s an example `main`

function:

```
main = do res <- return $
while []
(\a -> (length a) == 10)
$ do old <- get
new <- return $
old ++ [(length old)]
put new
sequence_ $ map (putStrLn . show) res
```

In this example, we perform a `while`

. Our initial state is an empty list. Our predicate tests that the length of the list is equal to 10. Then we enter our `State`

block where we append the length of the list to the end of the list. Finally, after the loop exits we `map (putStrLn . show)`

over the resulting list to print each element of the list to the console. The following will be displayed:

```
0
1
2
3
4
5
6
7
8
9
```

Ladies and Gentlemen, it walks like a duck, and quacks like a duck. Therefore, it must be a duck.