Pattern matching

Ruby 2.7 introduces pattern matching, it is nicely supported by dry-monads 1.3+.

Matching Result values

# presumably you do it in a class with `include Dry::Monads[:result]`

case value
in Success(Integer => x)
  # x is bound to an integer
in Success[:created, user]
  # user is bound to the second member
in Success(Date | Time)
  # date or time object
in Success[1, *]
  # any array starting with 1
in Success(String => s) if s.size < 100
  # only if `s` is short enough
in Success(counter: Integer)
  # matches Success(counter: 50)
  # doesn't match Success(counter: 50, extra: 50)
in Success(user: User, account: Account => user_account)
  # matches Success(user:, account:, else: ...)
  # user_account is bound to the value of the `:account` key
in Success()
  # corresponds to Success(Unit)
in Success(_)
  # general success
in Failure[:user_not_found]
  # matches Failure([:user_not_found]) or Failure[:user_not_found]
in Failure[error_code, *payload]
  # ...

In the snippet above, the patterns will be tried sequentially. If value doesn't match any pattern, an error will be thrown.

Matching Maybe

case value
in Some(Integer => x) if x > 0
  # x is a positive integer
in Some(Float | String)
  # ...
in None
  # ...

Matching List

case value
in List[Integer]
  # any list of size 1 with an integer
in List[1, 2, 3, *]
  # list with size >= 3 starting with 1, 2, 3
in List[]
  # empty list

Matching array values

dry-monads treats all wrapped array values as tuples rather than lists. For example, this will not work:

Success([1, 2, 3]) in Success(numbers) # => no match!

But this will:

Success([1, 2, 3]) in Success(one, two, three)

And this will too:

Success([1, 2, 3]) in Success[1, 2 ,3]

To capture an array value, use *:

Success([1, 2, 3]) in Success(*numbers)

At least for Failure values, people use tuples more often; this is why dry-monads treats all arrays as tuples. We could make Success/Failure behaviors different, but this would be even more unexpected.

octocatEdit on GitHub