OK - elegant error handling with result monads (alternative to Elixir `with` special form)

syntax
errors
Tags: #<Tag:0x00007f8ebfe3c880> #<Tag:0x00007f8ebfe3a198>

#21

To be honest I wish I could have used yield or return but out of the options I had the others all seamed worse. i.e. else and rescue.


#22

Well, you ‘could’. ^.^

OK.for do
  a <- safe_div(8, 2)
  b <- safe_div(a, 2)
  yield a + b
end

You’d not be able to use a function named ‘yield’ though, but I think that’s fine.

I’d still just vote for:

OK.for do
  a <- safe_div(8, 2)
  b <- safe_div(a, 2)
  a + b
end

It is perfectly and normally elixiry. :slight_smile:


#23

I certainly don’t disagree with you. I’m going to use it in some code and see how I feel about it. I’m also working on a writer monad for sending messages and am going to see how that looks with the separating after or not


#24

I made a block syntax for monad’y style do expressions in expede’s exceptional library as a PR if you want to see usage (though this one is for different style of error handling, the syntax is the same though): https://github.com/expede/exceptional/pull/18


#25

Version 1.9.0 released with new OK.try macro for normalising return values.

The syntax here is chosen to be basically the same as a natural try block but in this case without any errors being raised.

Example

require OK
import Raxx

OK.try do
  user <- fetch_user(1)             # `<-` operator means func returns {:ok, user}
  cart <- fetch_cart(1)             # `<-` again, {:ok, cart}
  order = checkout(cart, user)      # `=` allows pattern matching on non-tagged funcs
  saved_order <- save_order(order)
after
  response(:created)                # Value will be returned unwrapped
rescue
  :user_not_found ->
    response(:not_found)
  :could_not_save ->
    response(:internal_server_error)
end

This is a very nice way to write code that reliably returns the same type of value.
My favourite feature of this is it is familiar but raise can now be used for exceptions that should never happen.
i.e. programmer errors that should end up in bug tracking software as soon as possible.

With OK.for that was introduced in 1.8.0 I think that these are sane replacements for OK.with which had variable behaviour dependant on which code blocks had been defined.


#26

Version 1.9.1 released to fix warnings.

An warning that could occur when using pipes ~>> has been rectified.

The following code now will not raise any errors.

{:ok, num}
~>> double()

#27

Version 1.9.3 released to deprecate OK.with/1

The general purpose behaviour of OK.with has been replaced with two separate options

  • OK.for When a return value should be wrapped as an ok/error tuple
  • OK.try When error handling should be attempted, such as transforming errors to a 500 response.

See docs for details: https://hexdocs.pm/ok/1.9.3/readme.html


#28

Version 1.10.0: Add map/2 and ~> to treat result tuples as Functors.

The latest version of ok (1.10.0) has been release. It adds functionality to transform a value within an :ok tuple. e.g.

Examples

iex> {:ok, 5} ~> Integer.to_string
{:ok, "5"}

iex> {:error, :zero_division_error} ~> Integer.to_string
{:error, :zero_division_error}

iex> {:ok, "a,b"} ~> String.split(",")
{:ok, ["a", "b"]}

#29

Version 1.11.0 Add map_all/2 for working through lists.

Transform every element of a list with a mapping function.
The mapping function must return a result tuple.

If all of the result tuples are tagged :ok, then it returns a list tagged with :ok.
If one or more of the result tuples are tagged :error, it returns the first error.

Examples

  iex> OK.map_all(1..3, &safe_div(6, &1))
  {:ok, [6.0, 3.0, 2.0]}

  iex> OK.map_all([-1, 0, 1], &safe_div(6, &1))
  {:error, :zero_division}