<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Aug 9, 2015 at 12:07 AM, Garrett Smith <span dir="ltr"><<a href="mailto:g@rre.tt" target="_blank">g@rre.tt</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div id=":ej" class="a3s" style="overflow:hidden">The original calculate/3 mixes user facing behavior (print error<br>
messages) with a calculation. If your function returns a mishmash of<br>
completely unrelated values (e.g. the result of io:format and also the<br>
result of an area calculation) *it's a mess*.<br></div></blockquote></div><br>Another point to make could be the area/0 function:</div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_extra">area() -></div><div class="gmail_extra">  Answer = io:get_line("R)ectangle, T)riangle, or E)llipse > "),</div><div class="gmail_extra">  Shape = char_to_shape(hd(Answer)),</div><div class="gmail_extra">  case Shape of</div><div class="gmail_extra">    rectangle -> Numbers = get_dimensions("width", "height");</div><div class="gmail_extra">    triangle -> Numbers = get_dimensions("base", "height");</div><div class="gmail_extra">    ellipse -> Numbers = get_dimensions("major axis", "minor axis");</div><div class="gmail_extra">    unknown -> Numbers = {error, "Unknown shape " ++ [hd(Answer)]}</div><div class="gmail_extra">  end,</div><div class="gmail_extra"><br></div><div class="gmail_extra">  Area = calculate(Shape, element(1, Numbers), element(2, Numbers)),</div><div class="gmail_extra">  Area.</div><div class="gmail_extra"><br></div><div class="gmail_extra">First, projecting out of Answer with hd/1 can be solved by just pattern matching the first character out of the list. Of course, an empty list would fail here, but input parsing is hard and Barbie wants to go shopping. Second, you don't need to project out of numbers and bind it in every variant if you use the return value of the case expression to match the dimensions. Third, in addition to separating side-effects from computation, it is often smart to let errors return structural data which can be handled by a machine easily. And then provide a function which can interpret the machine-readable structure into human-readable form. Garrett omits the input that were failing. I like to keep it around in the error term[0]. Finally, it should be obvious the answer we wish to return is the area:</div></div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_extra">area() -></div><div class="gmail_extra">  [A | _] = io:get_line("R)ectangle, T)riangle, or E)llipse > "),</div><div class="gmail_extra">  {X, Y} = case char_to_shape(A) of</div><div class="gmail_extra">    rectangle -> get_dimensions("width", "height");</div><div class="gmail_extra">    triangle -> get_dimensions("base", "height");</div><div class="gmail_extra">    ellipse -> get_dimensions("major axis", "minor axis");</div><div class="gmail_extra">    unknown -> exit({unknown, A})</div><div class="gmail_extra">  end,</div><div class="gmail_extra"><br></div><div class="gmail_extra">  calculate(Shape, X, Y).</div><div><br></div><div>Lifting the case-expr to the top level as Garrett is doing is probably next up on the todo list. In general, Erlang likes to match data in structure rather than projecting components out of structure. I'd suggest you master both styles eventually in code, but matching can often avoid the scourge of boolean blindness in code.</div><div><br></div><div>[0] Caveat: think about when it is being garbage collected and how large that term is.</div><div><br></div>-- <br><div class="gmail_signature">J.</div>
</div></div>