We've just learned how to use structures - arrays in dictionaries - in awful. But having to access every index with a separate statement is obviously non-efficient - it would be much simpler if we could somehow execute an expression multiple times without copy-pasting. Here's where loops come into play.
:set &c i10 !while $c :write $c s' ' :sleep f1.0 :sub &c i1 !done :writeln sxBOOM!x
Above snippet demonstrates the use of awful's ewhilee loop. As can be seen, the loop is opened using the
!while construct, which should contain the looping condition. Upon encountering the loop's entry point, the condition will be evaluated and, if it's false, the loop will be skipped. End of loop code is marked using the
!done construct - upon meeting it, the interpreter jumps back to the appropriate
!while construct, evaluates the condition, and either executes loop code again, or jumps past loop end.
The ewhilee loop has one important feature, which sometimes can prove a drawback - since the condition is evaluated at the beginning of loop body, the statements inside may not got executed at all. But what if we want the loop body to always be executed at least once? Well, that's when we use the erepeate loop.
:set &cnt sss !repeat :writeln s'Random number: ' :random i0 i100 :write s'Another? y/n: ' :read &cnt !until :eq s'n' $cnt
Above snippet demonstrates the use of awful's erepeate loop. As we can see, the loop is opened using the
!repeat construct, which should not be given any arguments. After that, we write the statements we want to be repeated, and then close the loop body using the
!until construct. Similarly to
!until construct should be passed a condition - however, one important thing to remember is that whereas in the ewhilee loop we specified the condition to continue looping, in the erepeate loop we specify the condition to stop looping.
Sometimes you may want to have more than a single return point from a loop, or simply perform an operation only for selected arguments.
That's where the
!continue constructs come useful.
:set &sum i0 :set &i i0 !while :lt $i i100 :add &i i1 !if :eq i0 :mod $i i5 !continue !fi !if :eq i0 :mod $i i7 !continue !fi :add &sum $i !done :writeln s'Sum: ' $sum
The above snippet will calculate the sum of all numbers in 1-100 range, excluding numbers divisible by 5 or 7. The loop iterates from 1 to 100. If $i is divisible by 5 or 7, the
!continue construct is used to omit all other expressions present in the loop and jump back to the looping condition. To completely exit a loop, instead of returning to the looping condition, the
!break construct can be used.
:set &x &y i0 !while :lt $x i10 !while :lt $y i10 !if :eq i100 :mul $x $y :writeln s'x = ' $x s', y = ' $y !break i2 !fi :add &y i1 !done :add &x i1 !done
!continue constructs can be passed an additional, single argument, describing how many loops should it continue/break out of. This parameter must be a literal or a const; it is impossible to use a variable or an expression here.
:set &fib :arr i1 i1 :set &c i2 !repeat :set &fib[$c] :add $fib[:sub $c i1] $fib[:sub $c i2] :add &c i1 !until :eq $c i20
Loops work very nicely with arrays and dictionaries. In the example above, we use a simple loop to generate an array of 20 Fibonacci Numbers.
wikipage modified on 2014/0601/2317