[erlang-questions] Nested Case Statements v.s. multiple functions

dploop dploop@REDACTED
Tue Sep 26 07:16:01 CEST 2017


> "Obsessing over a rocket shape doesn't seem as important as the absence of any guard expression usage here.  Guards are unfortunately often ignored by Erlang programmers, though they are the one thing in Erlang without side-effects."

is_integer, is_zero is just a simplified example, and by coincidence, they can use in the guard. But in most situations you can't use guard, for example in game industry when player want to buy equipment, you should check if his coin is sufficient, and then you should check the number of equipment is right and then you  should check if the equipment is valid to exchange and so on. The complex business logic can't be easily solved by guard, and Nested Cases is inevitable.




dploop@REDACTED
 
From: Michael Truog
Date: 2017-09-26 12:48
To: dploop@REDACTED; Erlang-Questions Questions
Subject: Re: [erlang-questions] Nested Case Statements v.s. multiple functions
On 09/25/2017 07:40 PM, dploop@REDACTED wrote:
This problem also bothered me for a long time, so I write a parse transform to deal with it. To be specific, say we want to write a function which takes two integers and returns  the product and quotient of them.

muldiv(First, Second) ->
    case is_integer(First) of
        true ->
            case is_integer(Second) of
                true ->
                    Product = First * Second,
                    case Second =/= 0 of
                        true ->
                            Quotient = First div Second,
                            {ok, {Product, Quotient}};
                        false ->
                            {error, "Second must not be zero!"}
                    end;
                false ->
                    {error, "Second must be an integer!"}
            end;
        false ->
            {error, "First must be an integer!"}
    end.

Obsessing over a rocket shape doesn't seem as important as the absence of any guard expression usage here.  Guards are unfortunately often ignored by Erlang programmers, though they are the one thing in Erlang without side-effects.  Ideally, the source code is written to break when bad input is provided, and that doesn't require that you define the exception thrown for bad input.  A more minimal example without the added complexity here is below:

muldiv(First, 0)
    when is_integer(First) ->
    0;
muldiv(First, Second)
    when is_integer(First), is_integer(Second) ->
    {ok, {First * Second, First div Second}}.

That gets rid of all the noise and useless error returns, and instead lets the process die when there is a problem, unless the exception is caught and handled.  You could add another function clause to do an error/exit/throw on bad input, so it is a clear misuse of a function which would be checked with dialyzer, and dialyzer should be capable of inferring the types from the guards (the current code above should be known to only accept integers, and other usage would cause a dialyzer error... adding a bad input function clause would break that, but then that could be fixed by the Erlang type specification), even if the Erlang type specification isn't added.

Best Regards,
Michael

Ugly, at least I think this "rocket" is not beautiful. Even worse, if requirement changed, you should modify this code on a large scale. To avoid this problem, you can just rewrite your code like this
muldiv(First, Second) ->
    do@([esugar_do_transform_error ||
        case is_integer(First) of
        true -> return(next);
        false -> fail("First must be an integer!")
        end,
        case is_integer(Second) of
        true -> return(next);
        false -> fail("Second must be an integer!")
        end,
        Product = First * Second,
        case Second =/= 0 of
        true -> return(next);
        false -> fail("Second must not be zero!")
        end,
        Quotient = First div Second,
        return({Product, Quotient})
    ]).

This idea came from the Haskell's do grammer, and to use this grammer, you just need to write a error monad.

This parse transform code is one module of my esugar(An Erlang Syntactic Sugar Library) library, and the address is (https://github.com/dploop/esugar) 

I'm glad to discuss with you about how to use it or improve it(because I just write this toy for fun at the begining).




dploop@REDACTED
 
From: code wiget
Date: 2017-09-25 21:25
To: Erlang-Questions Questions
Subject: [erlang-questions] Nested Case Statements v.s. multiple functions
Hello everyone,
 
As I get further into Erlang, I am starting to realize that some of my functions have been getting pretty ugly with nested case statements. For example, I had a nested case statement that looked something like this:
 
Send_update(Arg1) ->
case do this(Arg1) of
{ok, [Val1, Val2]} ->  
case do_that(Val1, Val2) of
{ok, [Val3, Val4]} ->
case do_this2(…) of 
….
 
It continued into this for another few functions, you get the picture - its ugly, and it is hard to read. 
 
So I went and I converted it to a top level function that would then call lower level functions like so:
 
 
send_update(Arg1) ->  
     case ... of
         {ok, [Val1, Val2]} ->  
             send_update(check_indices, {Arg1, Val1, Val2});
         Else ->  
             lager:error("ERROR: ..")
     end.
send_update(check_indices, {Arg1, Arg2, Arg3}) ->
     case check_indices(Arg2, Arg3)of 
         true ->
             send_update(get_values, {Arg1, Arg3});
         false ->
             lager:error("EMERGENCY: ….")
     end;
send_update(get_values, {Arg1, Arg2}) ->
   ...
     case ... of  
         {ok, [Val1, Val2, VAl3]} ->
             send_update(send_value, {Arg1, Val1, Val2, Val3});
         Error ->  
             lager:error("ERROR: …")
     end;
send_update(send_value, {Arg1, Arg2, Arg3, Arg4}) ->
    …
     Do_something(Args),
     ok. 
 
 
Now that I look at it though, both don’t look right. They don’t look like something I would write in any other language where I would just have if’s and else’s.
 
Is this the proper way to write Erlang? I know everyone has their own style, but I assume there is some accepted form of writing functional programs with deep nests.
 
Thank you for your advice!
_______________________________________________
erlang-questions mailing list
erlang-questions@REDACTED
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
erlang-questions@REDACTED
http://erlang.org/mailman/listinfo/erlang-questions

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20170926/8958338e/attachment.htm>


More information about the erlang-questions mailing list