# Functor map

This post explores the map function in Purescript. Start a REPL by running these commands in a new directory:

```
mkdir test-functor; cd test-functor
spago init
spago install maybe arrays node-process
spago repl
```

## Context

Let’s consider this data type to represent a task:

```
> data Task = Task { name :: String, mem :: Int, cpu :: Int }
```

And this function to create a new task:

```
> mkTask name = Task { name, mem: 0, cpu: 0 }
> :t mkTask
String -> Task
```

(And copy paste this show instance to see the result in the REPL):

```
instance showTask :: Show Task where show (Task t) = "(Task " <> t.name <> ")"
```

We can create a task:

```
> task = mkTask "worker"
> task
(Task worker)
> :t task
Task
```

So far so good, nothing special to see here.

## Mapping mkTask

Here is the definition of `map mkTask`

:

```
> :t mkTask
String -> Task
> :t map mkTask
Functor f => f String -> f Task
```

`map mkTask`

is a function that takes a structure (called functor) holding a String, and it returns a new structure holding a Task. In otherwords, `map mkTask`

inject the `mkTask`

function inside the functor. In other otherwords, `map`

embellished `mkTask`

to work with functors.

Here are some example usages, using the Maybe Functor (don’t forget to `import Data.Maybe`

):

```
> map mkTask Nothing
Nothing
> map mkTask (Just "worker")
(Just (Task worker))
```

Or with the Array Functor:

```
> map mkTask ["worker1", "worker2"]
[(Task worker1), (Task worker2)]
```

Thanks to the Functor abstraction, we are able to modify the value contained in different structure using a common map function.

## Map definition

map is defined as follow:

```
> :t map
forall f a b. Functor f => (a -> b) -> f a -> f b
```

There are three parts (separated by `.`

and `=>`

):

`forall f a b`

is the quantification. That means there will be three type variables used in the definition:`f`

,`a`

, and`b`

. For more details read wasp-lang/haskell-handbook/forall.md.`Functor f`

is a constraint. That means the`f`

type variable needs to be a Functor. For more details read pursuit Functor`(a -> b) -> f a -> f b`

is the function signature. That means this function expects two arguments,`a -> b`

and`f a`

, and it returns a`f b`

.

Here `f`

is a type constructor, in the signature it is given a type. That means `f`

expects a type argument to become a final type. For more details read purescript-book/chapter3, or watch this An introduction to Haskell’s kinds video by Richard A. Eisenberg.

Now Let’s see why this works.

## Map type variables

The map definition is polymorphic, that means it can work in many scenarios depending on its arguments. We can observe how the type checker works by providing the argument one by one:

```
> :t map
forall f a b. Functor f => (a -> b) -> f a -> f b
> :t map mkTask
forall f. Functor f => f String -> f Task
> :t map mkTask []
Array Task
```

Notice how when using `mkTask`

the type variable `a`

becomes a String, and the `b`

becomes a Task. This is because these types are no longer variable after we use `mkTask`

: the polymorphic argument `a -> b`

becomes `String -> Task`

, and the other variable name occurences are replaced accordingly.

We can also change the order of the argument to provide the functor before the function using `flip`

:

```
> :t flip map
forall f a b. Functor f => f a -> (a -> b) -> f b
> :t flip map []
forall a b. (a -> b) -> Array b
> :t flip map ["x"]
forall b. (String -> b) -> Array b
> :t flip map ["x"] mkTask
Array Task
```

Notice how the type variable `f`

becomes an Array, and the `a`

becomes a String. This is because `["x"]`

is a `Array String`

when the function expect a `f a`

, thus the other variables are replaced accordingly:

- When
`Array String`

is used for an argument of type`f a`

, then `(a -> b) -> f b`

, becomes:`(String -> b) -> Array b`

.

This process can be refered to as specialization, and it is helpful to understand function signature by removing type variables.

## Motivating example

Finally, here is a last example to demonstrate map with `lookupEnv`

.

```
> import Node.Process
> :t lookupEnv
String -> Effect (Maybe String)
```

`lookupEnv`

expects a name, and it returns an `Effect`

containing an optional value.

```
> lookupEnv "USER"
(Just "tdecacqu")
```

Note that the REPL automatically perform the

`Effect`

.

We already saw how we can change the value of a Maybe using map, but `lookupEnv`

returns an extra Effect layer. Let’s consider this double map usage:

```
> :t map (map mkTask)
forall f g. Functor f => Functor g => f (g String) -> f (g Task)
```

We can use it to penetrate both the Effect and the Maybe functor to modify the final value in one shot while preserving the structure:

```
> :t map (map mkTask) (lookupEnv "USER")
Effect (Maybe Task)
> map (map mkTask) (lookupEnv "USER")
(Just (Task tdecacqu))
```

Map is so powerful it has an operator version: `<$>`

which let us rewrite this code as:

```
> map mkTask <$> lookupEnv "USER"
```

Which means, given the `Effect (Maybe String)`

returned by lookupEnv, we’ll inject `map mkTask`

into the `Effect`

, to convert the optional value into an optional Task.

And we can use this for any two functors combinaison, for example, a list of optional string:

```
> xs = [Nothing, Just "worker1", Just "worker2"] :: Array (Maybe String)
> map mkTask <$> xs
[Nothing, (Just (Task worker1)), (Just (Task worker2))]
```

And this concludes the exploration. Thanks for your time!

## Bonus: traverse

Well while you are here, here is `traverse`

:

```
> import Data.Traversable
> :t traverse
forall t m a b. Traversable t => Applicative m => (a -> m b) -> t a -> m (t b)
```

Nothing special here, we know how to read this. To recap, this definition means:

- There are 4 type variables:
`t`

,`m`

,`a`

and`b`

. `t`

is a Traversable, which is a foldable functor (and most Functor are Traversable), see this for more details: pursuit Traversable`m`

is an Applicative, and let’s not bother with what that means exactly, but just know that`Effect`

is an applicative: see its instance list: pursuit Effect

Thus, given a function `a -> m b`

, and a traversable `t a`

, traverse will produce a `m (t b)`

.

For example we can use traverse with lookupEnv because lookupEnv is compatible with `a -> m b`

, it is `String -> Effect (Maybe String)`

:

```
> :t traverse lookupEnv
forall t. Traversable t => t String -> Effect (t (Maybe String))
```

Notice how the lookupEnv definition sets the type variable `a`

to String, `m`

to Effect and `b`

to (Maybe String), leaving us with the last type variable `t`

.

This definition means that given a collection of string, `traverse lookupEnv`

will perform each individual lookup and return the result wrapped in a single Effect:

```
> :t traverse lookupEnv ["USER", "HOSTNAME"]
Effect (Array (Maybe String))
> traverse lookupEnv ["USER", "HOSTNAME"]
[(Just "tdecacqu"), (Just "localhost")]
```

This result uses 3 Functors: Effect, Array and Maybe. And of course we can use maps to penetrate all the layers:

```
> :t map (map mkTask) <$> traverse lookupEnv ["USER", "HOSTNAME"]
Effect (Array (Maybe Task))
> map (map mkTask) <$> traverse lookupEnv ["USER", "HOSTNAME", "OOPS"]
[(Just (Task tdecacqu)), (Just (Task localhost)), Nothing]
```

Or using function composition:

```
> traverse (map (map mkTask) <<< lookupEnv) ["USER", "HOSTNAME"]
[(Just (Task tdecacqu)), (Just (Task localhost))]
```

Which is really convenient as we don’t have to unwrap anything. Using map we modify `lookupEnv`

to convert a traversable structure of `String`

into `Task`

s by reading their value from the environment:

```
> :t traverse (map (map mkTask) <<< lookupEnv)
forall t. Traversable t => t String -> Effect (t (Maybe Task))
```

Cheers o/