# monads

# monads

Monads for Crystal.

Inspired by https://github.com/dry-rb/dry-monads

## Installation

Add this to your application's `shard.yml`

:

```
dependencies:
monads:
github: alex-lairan/monads
```

## Usage

```
require "monads"
```

Many monads exist.

### Maybe(T)

The *Maybe* monad helps to avoid `nil`

and chain instructions.

There are two kinds of *Maybe*, `Just`

and `Nothing`

.

#### Just(T)

This is just a value.

```
Monads::Just.new(5)
```

#### Nothing(T)

This is an absence of value.

```
Monads::Nothing(Int32).new
```

### Either(E, T)

The *Either* monad helps to manage *errors* at the end of the chain of instructions.

There are two kinds of *Either*, `Right`

and `Left`

.

#### Right(T)

This is just a value.

```
Monads::Right.new("Hello world")
```

#### Left(E)

This is an error.

```
Monads::Left.new("User password is incorrect")
```

### List(T)

The *List* monad helps to manipulate an *Array* like a monad.

```
Monads::List[1, 6, 4, 2]
```

#### head

`head`

returns the first element wrapped within a `Maybe`

.

#### tail

`tail`

returns the list without the first element.

### Try(T)

The `Try`

monad is a layer between *Object Oriented Exception* and *Fuctional Programming Monads*.
It can be transformed into a `Maybe`

or an `Either`

.

### Task(T)

The `Task`

monad is a parallelized `Try`

monad.
Its goal is to use the power of fibers with monads.

### How to use a monad ?

Monads have some methods which help to chain instructions.

`Try`

and `Task`

monads should be translated into a `Maybe(T)`

or an `Either(Exception, T)`

one.

#### fmap

The `fmap`

procedure modify the internal value of a monad.

This doesn't affect `Nothing`

and `Left`

monads.

Example:

```
value = Monads::Just.new(5)
.fmap(->(x : Int32) { x.to_s })
.fmap(->(x : String) { x + "12" })
.fmap(->(x : String) { x.to_i })
.value!
value.should eq(512)
```

#### bind

The `bind`

procedure allows to create a whole new monad from the internal data of another.

This doesn't affect `Nothing`

and `Left`

monads.

Example:

```
value = Monads::Just.new(5)
.bind(->(x : Int32) { Monads::Try(Int32).new(-> { x / 0}).to_maybe })
value.should eq(Monads::Nothing(Int32).new)
```

## Development

Clone then let's go, no special requirements.

## Contributing

- Fork it (https://github.com/alex-lairan/monads/fork)
- Create your feature branch (
`git checkout -b my-new-feature`

) - Commit your changes (
`git commit -am 'Add some feature'`

) - Push to the branch (
`git push origin my-new-feature`

) - Create a new Pull Request

## Contributors

- alex-lairan Alexandre Lairan - creator, maintainer
- moba1 moba - maintainer