---
title: Introduction
description: Common monads for Ruby
layout: gem-single
type: gem
name: dry-monads
sections:
  - getting-started
  - maybe
  - result
  - do-notation
  - try
  - list
  - task
  - validated
  - case-equality
  - tracing-failures
  - pattern-matching
  - unit
---

dry-monads is a set of common monads for Ruby. Monads provide an elegant way of handling errors, exceptions and chaining functions so that the code is much more understandable and has all the error handling, without all the `if`s and `else`s. The gem was inspired by the [Kleisli](https://github.com/txus/kleisli) gem.

What is a monad, anyway? Simply, [a monoid in the category of endofunctors](https://stackoverflow.com/questions/3870088/a-monad-is-just-a-monoid-in-the-category-of-endofunctors-whats-the-proble%E2%85%BF). The term comes from category theory and some believe monads are tough to understand or explain. It's hard to say why people think so because you certainly don't need to know category theory for using them, just like you don't need it for, say, using functions.

Moreover, the best way to develop intuition about monads is looking at examples rather than learning theories.

## How to use it?

Let's say you have code like this

```ruby
user = User.find_by(id: params[:id])

if user
  address = user.address
end

if address
  city = address.city
end

if city
  state = city.state
end

if state
  state_name = state.name
end

user_state = state_name || "No state"
```

Writing code in this style is tedious and error-prone. There were created several "cutting-corners" means to work around this issue. The first is ActiveSupport's `.try` which is a plain global monkey patch on `NilClass` and `Object`. Another solution is using the Safe Navigation Operator `&.` introduced in Ruby 2.3 which is a bit better because this is a language feature rather than an opinionated runtime environment pollution. However, some people think these solutions are hacks and the problem reveals a missing abstraction. What kind of abstraction?

When all objects from the chain of objects are there we could have this instead:

```ruby
state_name = User.find_by(id: params[:id]).address.city.state.name
user_state = state_name || "No state"
```

By using the `Maybe` monad you can preserve the structure of this code at a cost of introducing a notion of `nil`-able result:

```ruby
state_name = Maybe(
  User.find_by(id: params[:id])
).maybe(&:address).maybe(&:city).maybe(&:state).maybe(&:name)

user_state = state_name.value_or("No state")
```

`Maybe(...)` wraps the first value and returns a monadic value which either can be a `Some(user)` or `None` if `user` is `nil`. `maybe(&:address)` transforms `Some(user)` to `Some(address)` but leaves `None` intact. To get the final value you can use `value_or` which is a safe way to unwrap a `nil`-able value. In other words, once you've used `Maybe` you _cannot_ hit `nil` with a missing method. This is remarkable because even `&.` doesn't save you from omitting `|| "No state"` at the end of the computation. Basically, that's what they call "Type Safety".

A more expanded example is based on _composing_ different monadic values. Suppose, we have a user and address, both can be `nil`, and we want to associate the address with the user:

```ruby
user = User.find_by(id: params[:user_id])
address = Address.find_by(id: params[:address_id])

if user && address
  user.update(address_id: address.id)
end
```

Again, this implies direct work with `nil`-able values which may end up with errors. A monad-way would be using another method, `bind`:

```ruby
maybe_user = Maybe(User.find_by(id: params[:user_id]))

maybe_user.bind do |user|
  maybe_address = Maybe(Address.find_by(id: params[:address_id]))

  maybe_address.bind do |address|
    user.update(address_id: address.id)
  end
end
```

One can say this code is opaque compared to the previous example but keep in mind that in _real code_ it often happens to call methods returning `Maybe` values. In this case, it might look like this:

```ruby
find_user(params[:user_id]).bind do |user|
  find_address(params[:address_id]).bind do |address|
    Some(user.update(address_id: address.id))
  end
end
```

Finally, since 1.0, dry-monads has support for [`do` notation](docs::do-notation) which simplifies this code even more, making it almost regular yet `nil`-safe:

```ruby
user = yield find_user(params[:user_id])
address = yield find_address(params[:address_id])

Some(user.update(address_id: address.id))
```

Another widely spread monad is `Result` (also known as `Either`) that serves a similar purpose. A notable downside of `Maybe` is plain `None` which carries no information about where this value was produced. `Result` solves exactly this problem by having two constructors for `Success` and `Failure` cases:

```ruby
def find_user(user_id)
  user = User.find_by(id: user_id)

  if user
    Success(user)
  else
    Failure(:user_not_found)
  end
end

def find_address(address_id)
  address = Address.find_by(id: address_id)

  if address
    Success(address)
  else
    Failure(:address_not_found)
  end
end
```

You can compose `find_user` and `find_address` with `bind`:

```ruby
find_user(params[:user_id]).bind do |user|
  find_address(params[:address_id]).bind |address|
    Success(user.update(address_id: address.id))
  end
end
```

The inner block can be simplified with `fmap`:

```ruby
find_user(params[:user_id]).bind do |user|
  find_address(params[:address_id]).fmap |address|
    user.update(address_id: address.id)
  end
end
```

Or, again, the same code with `do`:

```ruby
user = yield find_user(params[:user_id])
address = yield find_address(params[:address_id])

Success(user.update(address_id: address.id))
```

The result of this piece of code can be one of `Success(user)`, `Failure(:user_not_found)`, or `Failure(:address_not_found)`. This style of programming is called "Railway Oriented Programming" and you can check out [dry-transaction](/gems/dry-transaction) and watch a [nice video](https://fsharpforfunandprofit.com/rop/) on the subject. Also, see [dry-matcher](/gems/dry-matcher) for an example of how to use monads for controlling the flow of code with a result.

## A word of warning

Before `do` came around here was a warning about over-using monads, turned out with `do` notation code does not differ much from regular Ruby code. Just don't wrap everything with `Maybe`, come up with conventions.

If you're interested in functional programming in general, consider learning other languages such as Haskell, Scala, OCaml, this will make you a better programmer no matter what programming language you use on a daily basis. And if not earlier then maybe after that, dry-monads will become another instrument in your Ruby toolbox :)

## Credits

dry-monads is inspired by Josep M. Bach’s [Kleisli](https://github.com/txus/kleisli) gem and its usage by [dry-transaction](/gems/dry-transaction/) and [dry-types](/gems/dry-types/).
