[erlang-questions] Why doesn't Erlang has return statement?

Alex Wilson alex@REDACTED
Wed Dec 17 02:06:56 CET 2014

> On 17 Dec 2014, at 10:31 am, aman mangal <mangalaman93@REDACTED> wrote:
> > Moreover, is there a good alternate to avoid nested case statements?
> Why avoid them?  Give a *real* example where nested case expressions
> (not “statements”, Erlang doesn’t strictly speaking *have* “statements”)
> are a problem.
> When I am using pattern matching, I wonder what if the function returned something else. More specifically the return could be {ok, Result} | {error, Reason}. This can happen in a sequence of statements and I end up using nested case expressions or calling one functions after another to handle both the cases separately.

You could consider something like a monad, perhaps. I know "monad" is a horrible functional programming word that makes people go "OMG THAT'S TOO HARD", but it's a pretty clean way to deal with errors sometimes.

https://github.com/rabbitmq/erlando#do has an example of implementing do-notation for monads in Erlang using a parse-transform. The error monad example is kind of interesting.

You can do the same thing without the parse-transform by having a function like this one:

threaduntil([], Acc) -> Acc;
threaduntil([Fun | Rest], Acc) ->
	case Fun(Acc) of
		{error, E} -> {error, E};
		Acc1 -> threaduntil(Rest, Acc1)

So you call this with a list of funs, and whatever the output from one fun is, becomes the argument to the next one on the list, until either it reaches the end of the list (and returns the last return value), or one of the funs returns {error, _} -- then it short-circuits and returns the error straight away.

It's not the lowest-overhead thing ever (making all those funs and executing them), but usually you see this kind of thing when dealing with i/o or high-level control logic that doesn't have to be the fastest-executing thing ever.

I've used this pattern (and the erlando do-transform specifically) quite a lot to avoid chains of Thing1 = blah(Thing), Thing2 = foo(Thing1), Thing3 = bar(Thing2)... etc etc, and also to deal with situations where deeply nested errors need to produce a well-defined return value. I have a personal distaste for try/catch, so I prefer to choose between either crashing the process, or using this kind of approach.

More information about the erlang-questions mailing list