<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace">Have you considered laying it out somewhat differently?</div><div class="gmail_default" style="font-family:monospace,monospace">  (    if ... then</div><div class="gmail_default" style="font-family:monospace,monospace">  else if ... then</div><div class="gmail_default" style="font-family:monospace,monospace">  else if ... then</div><div class="gmail_default" style="font-family:monospace,monospace">  else</div><div class="gmail_default" style="font-family:monospace,monospace">  )</div><div class="gmail_default" style="font-family:monospace,monospace">It's *really* not a good idea to put semicolons at the end of lines</div><div class="gmail_default" style="font-family:monospace,monospace">as they are far too easy to confuse with commas.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, 22 Jul 2019 at 18:16, Julian Fondren <<a href="mailto:jfondren@minimaltype.com">jfondren@minimaltype.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello,<br>
<br>
Please consider the following. I realize that daytype/1 would be<br>
better as just a bunch of disjunctions, but I'm using the example to<br>
show off different ways to format Mercury code:<br>
<br>
   :- type days<br>
       --->    sunday<br>
       ;       monday<br>
       ;       tuesday<br>
       ;       wednesday<br>
       ;       thursday<br>
       ;       friday<br>
       ;       saturday.<br>
<br>
   :- func daytype(days) = string.<br>
   daytype(D) = R :-<br>
       (<br>
           D = wednesday<br>
       -><br>
           R = "humpday"<br>
       ;<br>
           (D = sunday; D = saturday)<br>
       -><br>
           R = "weekend"<br>
       ;<br>
           R = "workday"<br>
       ).<br>
<br>
if/then/else seems to be the recommended style, but, I find it<br>
impossible to format in a pleasing way. Here are some attempts, and<br>
my problems with them:<br>
<br>
   % this feels like the natural way.<br>
   % but this is a level of indentation too many.<br>
   % it looks OK here but not next to (A;B;C;D).<br>
   daytype(D) = R :-<br>
       (<br>
           if D = wednesday then<br>
               R = "humpday"<br>
           else if (D = sunday; D = saturday) then<br>
               R = "weekend"<br>
           else<br>
               R = "workday"<br>
       ).<br>
<br>
vs.<br>
<br>
   % Mercury stdlib seems to have settled on this style.<br>
   % the initial 'if' looks unbalanced vs. the rest of the code.<br>
   daytype(D) = R :-<br>
       ( if D = wednesday then<br>
           R = "humpday"<br>
       else if (D = sunday; D = saturday) then<br>
           R = "weekend"<br>
       else<br>
           R = "workday"<br>
       ).<br>
<br>
   % trying to fix the previous version.<br>
   % new problem: inconsistent indentation.<br>
   daytype(D) = R :-<br>
       ( if D = wednesday then<br>
           R = "humpday"<br>
         else if (D = sunday; D = saturday) then<br>
           R = "weekend"<br>
         else<br>
           R = "workday"<br>
       ).<br>
<br>
   % trying to fix the inconsistency.<br>
   % new old problem: this is a level of indentation too many.<br>
   daytype(D) = R :-<br>
     ( if D = wednesday then<br>
         R = "humpday"<br>
       else if (D = sunday; D = saturday) then<br>
         R = "weekend"<br>
       else<br>
         R = "workday"<br>
     ).<br>
<br>
Even if horizontal formatting is generally discouraged as a<br>
maintenance hassle, Mercury styling uses it a lot (and somewhat more<br>
conveniently than normal since it's aligned to tab stops), and it<br>
just looks really, really nice, for code that's not going to change<br>
a lot.<br>
<br>
   daytype(D) =<br>
       (<br>
           D = wednesday               ->  "humpday";<br>
           (D = sunday; D = saturday)  ->  "weekend";<br>
                                           "workday"<br>
       ).<br>
<br>
With if/then:<br>
<br>
   % This is somehow intolerable. With punctuation it looks like math<br>
   % you'd write freehand on paper. Maybe that's why I like that<br>
   % version.<br>
   daytype(D) =<br>
       (<br>
           if D = wednesday                    then "humpday"<br>
           else if (D = sunday; D = saturday)  then "weekend"<br>
                                               else "workday"<br>
       ).<br>
<br>
*Syntax* issues with languages, I'd normally disregard as trivial,<br>
but I don't think *formatting* is trivial. Formatting is so<br>
important that<br>
<br>
   1. languages like Python, Haskell, Nim, make it meaningful.<br>
<br>
   2. languages like Go (gofmt), Ada (gnatpp), Elm, make it<br>
      automatic. You don't format your code; a code prettifier does.<br>
<br>
   3. JavaScript speakers like Douglas Crockford pretend that<br>
      automatic semicolon insertion is a scaaaary, spooooky<br>
      nondeterministic process that you can't trust with your code,<br>
      in order to persuade devs to always use semicolons even though<br>
      JS doesn't actually need them, because there are exactly *two*<br>
      minor formatting problems that come up if you avoid semicolons<br>
      as a rule.<br>
<br>
   4. ReasonML and Elixir are successful and popular 'languages' that<br>
      are just skins over existing languages that are somewhat<br>
      more annoying (Erlang string literals produce list(char) and to<br>
      avoid that you write uglier <<"blah">> binary literals; OCaml<br>
      has a toplevel/non-toplevel syntax distinction that people so<br>
      routinely fail to understand that you'll see unnecessary ;;<br>
      double semicolons all the time in newbie OCaml code).<br>
<br>
Maybe this is untrue, but my assumption for a while was that<br>
if/then/else was added to Mercury in the first place because people<br>
learning Mercury complained about formatting problems with the<br>
Prolog-style conditionals. This is odd as the new syntax retains any<br>
problem you'd have with the old syntax, but, even if people are<br>
aggravated by something, this doesn't mean they *recognize* what<br>
specifically they find aggravating. Maybe the formatting aggravation<br>
was always mis-explained as "words are easier to read than<br>
punctuation":<br>
<br>
   1. other languages use words rather than punctuation (true, but<br>
      irrelevant)<br>
   2. other languages don't need to parenthesize their conditionals<br>
      to mark where the conditionals end<br>
<br>
Maybe the water's long under the bridge, but an 'end' token<br>
instantly fixes the syntax in my view.<br>
<br>
   daytype(D) = R :-<br>
       if D = wednesday then<br>
           R = "humpday"<br>
       else if (D = sunday; D = saturday) then<br>
           R = "weekend"<br>
       else<br>
           R = "workday"<br>
       end.<br>
<br>
...<br>
<br>
Well, having said all that, I've already realized that the<br>
unbalanced-if is what the stdlib is going with, so I'll try that and<br>
see if it eventually stops bothering me.<br>
<br>
I do think that the tutorial should reflect this style if that's<br>
what's recommended. Right now the tutorial has<br>
<br>
   fib(N, X) :-<br>
       (   if    N =< 2<br>
           then  X = 1<br>
           else  fib(N - 1, A), fib(N - 2, B), X = A + B<br>
       ).<br>
<br>
which is just...<br>
<br>
1. an indention too many<br>
2. the N =< 2 column isn't on a (4spc) tab stop. If fixed to lie on<br>
    a tab stop (for writing/editing convenience), it's excessively<br>
    indented and looks ugly.<br>
3. that final 'else' looks bad and every other way to reformat it<br>
    looks much, much worse.<br>
<br>
And then later, a four-space indentation, followed by a three-space<br>
indentation for if/then/else keywords, followed by a two-space<br>
indentation for the body of the conditional:<br>
<br>
   main(!IO) :_<br>
       io.read_line_as_string(Result, !IO),<br>
       (  if<br>
            Result = ok(String),<br>
            string.to_int(string.strip(String), N)<br>
          then<br>
            io.format("fib(%d) = %d\n", [i(N), i(fib(N))], !IO)<br>
            main(!IO)<br>
          else<br>
            io.format("I didn't expect that...\n", [], !IO)<br>
       ).<br>
<br>
I actually like Mercury's syntax, and how the language looks<br>
overall. I was even happy to discover that the omnipresent<br>
parentheses are really just mathematical parentheses for<br>
grouping, and that this is valid (if inadvisable):<br>
<br>
   daytype(D) = R :-<br>
       (D = sunday; D = saturday),<br>
       R = "weekend";<br>
<br>
       (D = monday; D = tuesday; D = thursday; D = friday),<br>
       R = "workday";<br>
<br>
       D = wednesday,<br>
       R = "humpday".<br>
<br>
But I don't think anyone could read the tutorial, and try to<br>
recreate the examples as they're shown, and come to any other<br>
conclusion than that Mercury conditionals are very annoying to<br>
format. While reproducing the second example, in vim, I used visual<br>
block mode to delete a single space, rather than actually recreate<br>
that 3-space indent.<br>
_______________________________________________<br>
users mailing list<br>
<a href="mailto:users@lists.mercurylang.org" target="_blank">users@lists.mercurylang.org</a><br>
<a href="https://lists.mercurylang.org/listinfo/users" rel="noreferrer" target="_blank">https://lists.mercurylang.org/listinfo/users</a><br>
</blockquote></div>