`<-`

is valid in `do`

-notation and it doesn’t just assign a value but also “unwraps” or “extracts” it from a monad.

Let us look at a `Maybe Int`

example. We will take `Just 1`

and increment it by `1`

.

Here is the first attempt with `let`

:

```
onePlusOne :: Maybe Int
onePlusOne = do
let valueInMaybe = Just 1
Just (valueInMaybe + 1)
```

This code won’t compile obviously, because `let valueInMaybe = Just 1`

is just a binding; `valueInMaybe`

is `Just 1`

and I can’t add one to it, `Just 1`

isn’t of the same type as `1`

, it isn’t an `Int`

.

But consider:

```
onePlusOne :: Maybe Int
onePlusOne = do
valueInMaybe <- Just 1
Just (valueInMaybe + 1)
```

This code compiles and returns `Just 2`

. `valueInMaybe <- Just 1`

extracts `1`

from `Just 1`

and binds it to `valueInMaybe`

. In the next line, we sum 2 integers, `valueInMaybe`

and `1`

. Finally we wrap the result `2`

back into a `Maybe`

. And we have to, because `do`

-notation is a jail, we can’t escape from; if we’re working with a specific monad, we have to give this monad back at the end.

So what happens if ` valueInMaybe <- Nothing`

? The next line won’t be executed and the function will return `Nothing`

. This is the reason why we have to return `Maybe Int`

at the end and not just `Int`

, because the result can be `Nothing`

.