# Thinking Functionally: How types work with functions

Now that we have some understanding of functions, we'll look at how types work with functions, both as domains and ranges. This is just an overview.

First, we need to understand the type notation a bit more. We’ve seen that the arrow notation "->" is used to show the domain and range (`domain -> range` which is the same as `Func<domain, range>`)

## Function types as parameters

A function that takes other functions as parameters, or returns a function, is called a higher-order function (sometimes abbreviated as HoF). They are used as a way of abstracting out common behaviour. These kinds of functions are extremely common in language-ext; most of the types use them. You may have already experienced them from using LINQ functions like `Select` and `Where`.

Consider a function `EvalWith5ThenAdd2`, which takes a function as a parameter, then evaluates the function with the value `5`, and adds `2` to the result:

```    static int EvalWith5ThenAdd2(Func<int, int> fn) =>
fn(5) + 2;```

You can see that the domain is `(int -> int)` (`Func<int, int>`) and the range is `int`. What does that mean? It means that the input parameter is not a simple value, but a function, and what's more is restricted only to functions that map ints to ints. The output is not a function, just an `int`.

Let’s try it:

```    Func<int, int> add1 = x => x + 1;  // define a function of type (int -> int)

`add1` is a function that maps ints to ints, as we can see from its signature. So it is a valid parameter for the `EvalWith5ThenAdd2` function. And the result is `8`.

Here’s another one:

```    Func<int, int> times3 = x => x * 3; // a function of type (int -> int)
int x = EvalWith5ThenAdd2(times3)   // x == 17```

`times3` is also a function that maps ints to ints, as we can see from its signature. So it is also a valid parameter for the `EvalWith5ThenAdd2` function. And the result is `17`.

Note that the input is sensitive to the types. If our input function uses floats rather than ints, it will not work. For example, if we have:

```    Func<float, float> times3float = x => x * 3.0;  // a function of type (float->float)

Evaluating this will give an error, meaning that the input function should have been an int->int function (`Func<int, int>`).

### Functions as output

A function value can also be the output of a function. For example, the following function will generate an “adder” function that adds using the input value.

```    static Func<int, int> AdderGenerator(int numberToAdd) =>

The signature is:

``````    int -> (int -> int)
``````

which means that the generator takes an int, and creates a function (the “adder”) that maps ints to ints. It can be represented as `Func<int, Func<int, int>>`. Let’s see how it works:

```    var add1 = AdderGenerator(1);

This creates two adder functions. The first generated function adds 1 to its input, and the second adds 2. Note that the signatures are just as we would expect them to be.

``````    add1 = int -> int
``````

And we can now use these generated functions in the normal way. They are indistinguishable from functions defined explicitly

```    int x = add1(5);   // x == 6
int y = add2(5);   // y == 7```

## The `Unit` type

When programming, we sometimes want a function to do something without returning a value. Consider the function `PrintInt`, defined below. The function doesn’t actually return anything. It just prints a `string` to the console as a side effect.

```    void PrintInt(int x)
{
Console.WriteLine(x);
}```

So what is the signature for this function?

We can't put `void` into a `Func` in C#. That is because in type-theory `void` represents a type with no possible values (it has no domain). And therefore it can't be instantiated. This has lead to the disaster zone which is `Action` and `Func`, where `Action` is a `Func` that doesn't return a value. If we go back to the core concepts of mathematical functions from an earlier episode, we must have a "range" or a "codomain" for our "domain". i.e. `domain -> range`.

So what is the `range` when we have nothing to return? That's where `Unit` comes in. Unlike `void` it can be instantiated. It is a type that can have one possible value, itself: `unit`. If you think of how `bool` can have two possible values: `true` and `false`, then `Unit` is a type that has only one possible value: `unit`.

Even if a function returns no output, it still needs a range. There are no "void" functions in mathematics-land. Every function must have some output, because a function is a mapping, and a mapping has to have something to map to!

So in language-ext, functions don't return `void` they return `Unit`. You should get used to using `Unit` instead of `void` as a matter of 'good hygiene'. You will find that it is very useful as you become more experienced at functional programming in general.

`    Unit WhatIsThis() => unit;`

The signature of this should be `Unit -> Unit`. But if we want to represent that as a `Func` then it will be `Func<Unit>`. So what's going on? In functional languages the unit type is often represented as `()`. So when you see `WhatIsThis()` with the trailing `()` you can read that as "pass the unit value to the function `WhatIsThis`". Unfortunately C# interprets that slightly differently, and considers `()` as an invocation with zero values. This is one of the areas where C# method signatures don't quite match our functional ideals.

To represent this fully we'd need to write:

`    Unit WhatIsThis(Unit _) => unit;`

But that's overkill and doesn't help anybody. However when working with `Func<domain, range>`, it can sometimes be useful for the domain to be a `Unit`. This happens rarely, but shouldn't be ignored. The most useful aspect of `Unit` is when representing the range, and returning a concrete codomain rather than an empty one.

## Forcing unit types with the ignore function

In some cases the compiler requires a unit type and will complain. For example, both of the following will be compiler errors:

`    Unit DoSomething() => 1 + 1;`

You can use the `ignore` function in the `Prelude` to ignore the result of computation whilst maintaining the expression:

`    Unit DoSomething() => ignore(1 + 1);`

## Other types

The types discussed so far are just the basic types. These types can be combined in various ways to make much more complex types. A full discussion of these types will have to wait for another series, but meanwhile, here is a brief introduction to them so that you can recognise them in function signatures.

• The “tuple” types. These are pairs, triples, etc., of other types. For example `("hello", 1)` is a tuple made from a `string` and an `int`. The comma is the distinguishing characteristic of a tuple – if you see a comma in C#, it is almost certainly part of a tuple! (parameter lists can be seen as tuples if you think about it).

• The immutable collection types. The most common of these are lists (`Lst`), sequences (`Seq`), arrays (`Arr`), maps (`Map`), and sets (`Set`). Lists and arrays are fixed size, while sequences come in two flavours: `IEnumerable` and `Seq`. `IEnumerable` are potentially infinite whereas `Seq` has many of the behaviours of `IEnumerable` without the potential downside of multiple evaluations (although this rules it out of infinite sequences).

```    Lst<int> list = List(1, 2, 3);
Lst<string> list = List("a", "b", "c");
Seq<int> seq = Seq(Range(1, 10));
Arr<int> arr = Array(1, 2, 3);```
• The option type. This is a simple wrapper for objects that might be missing. There are two cases: `Some` and `None`.
```    Option<int> option = Some(1);
Option<int> option = None;```

NEXT: Currying

##### Clone this wiki locally
You can’t perform that action at this time.
Press h to open a hovercard with more details.