That's the result of Elixir being dynamic and not having built-in monads. You always have to check the docs/code.
> The other thing is that sometimes a function can both throw an exception and also return a success tuple.
I would say this is just poor design (though maybe someone could point me to an exemplary use of this?). As I see it (which is from how I've read it described and how most good lib do it):
- If function can error and the caller can do something about it, return :ok/:error.
- If the caller can't do anything about the error, raise.
- If the function can't fail, return a raw value.