0

I need to achieve in a cl-loop the following conditional written in pseudocode.

if (flag1) {
  if (flag2) {return ...} 
} else {
  return ...
}

Note that it is equivalent to

if (flag1 && flag2) {return ...} 
if (!flag1) {return ...}

which undesirably repeats flag1 twice.

What I have done is:

(cl-loop ...
  if (flag) do 'nothing and
    if (...) return ... end
  else 
    return ...)

The do 'nothing and looks a bit hacky to me, but I cannot omit it as it's part of the nested if syntax. Are there alternative (and clearer) ways to do this ? Maybe using cl-block or by outsourcing the conditionals to another function ?

EDIT (further clarification):

The use of the keywords and and end could help to disambiguate dangling else (which is the conditional pattern given in this question).

Inspired from @John Kitchin's example, consider the following snippets and note the indentation:

(cl-loop
 with flag1 = nil
 with flag2 = t
 if flag1 return 3
 if flag2 return 1
 else return 2)

returns 1.

On the other hand,

(cl-loop
 with flag1 = nil
 with flag2 = t
 if flag1 return 3 and
   if flag2 return 1 end
 else return 2)

returns 2.

Thus, to accomplish the desired conditional, the keywords and and end are required.

Now, going back to the initial question: how to achieve the latter conditional, without a clause at the return 3 position, ignoring potential infinite loops ?

It seems impossible per se: according to the documentation, the <clause> in if <condition> <clause> should be an accumulation, do, return, if, or unless clause.

My solution is replacing it with do 'nothing or do (ignore) to fulfill the documentation's requirement, or use the equivalent yet repetitive conditional (undesired, see above), but I'm looking for alternatives.

Firmin Martin
  • 1,265
  • 7
  • 23
  • Your latest edit would never execute the inner `if` clause at all (it would just return 3), and your original example may be an infinite loop when the first test passes and the second fails? I'm no expert with the `loop` language, but the question still seems a bit confusing. – phils Jul 01 '21 at 06:22
  • @phils Do you mean "it would never return 3" ? That's the reason I want to get rid of this clause. Yeah, I'm aware of the potential infinite loop (that's why in my latest edit I assigned those values). In my real-world case, I made sure it doesn't happen at all. – Firmin Martin Jul 01 '21 at 06:36
  • I mean that `return 3 and ...` will just return 3 and not do the `...`. – phils Jul 01 '21 at 06:58
  • John Kitchin's answer looks good to me, and I can't tell what you want from your edits. – phils Jul 01 '21 at 07:01
  • `(cl-loop if flag1 if flag2 return 1 end else return 2)` matches what I thought you wanted (the infinite loop condition notwithstanding). – phils Jul 01 '21 at 07:07
  • @phils I edited my question to make it less confusing. Ok I see your confusion, return is a bad example, let's say `collect`... – Firmin Martin Jul 01 '21 at 07:08
  • @phils I tried it and it does work! Do you care to make it an answer? I probably thought that the `and` was mandatory to make nested `if`. – Firmin Martin Jul 01 '21 at 07:12
  • It's the same as John Kitchin's answer. I only replaced the `else return 0` of the inner clause with `end` (which you had already figured out). I've edited that answer to include my variant of the code. – phils Jul 01 '21 at 07:51

1 Answers1

2

I think this is what you want:

(let ((flag1 nil)
      (flag2 nil))
  (cl-loop
   if flag1
   if flag2 return 1
   else return 0
   else return 2))

if flag1 is nil, you get 2 if flag1 is t, and flag2 is nil you get 0 if flag1 is t, and flag2 is t you get 1


Or to replicate the original pseudo code (complete with its infinite loop scenario):

  (cl-loop
   if flag1
   if flag2 return 1 end
   else return 2)
phils
  • 48,657
  • 3
  • 76
  • 115
John Kitchin
  • 11,555
  • 1
  • 19
  • 41
  • Thanks for the answer. It looks perfect until I realized that my question wasn't clear enough. I just edited it. In short, what if I want to remove the `else return 0` and keep the `if flag1` as it is while keeping the semantics given in the question ? – Firmin Martin Jul 01 '21 at 04:21
  • Thanks for the edit @phils. I also have the issue to indent nested if or conditional clause in `cl-loop`: `indent-region` just align everything as shown in the upper part of this answer. Perhaps, any of you might have an answer or remark for [this long-standing question](https://emacs.stackexchange.com/questions/40781/indent-cl-loop-to-respect-if-else-statements). – Firmin Martin Jul 01 '21 at 08:16