# Loops, and higher order functions Efficient use of these functions can greatly simplify your programs and speed them up, as these functions will internalize most of the operations that need to be applied on multiple values at the same time. Most of them take a `list` argument which can be any iterable structure in scarpet, including generators, like `rect`, or `range`, and maps, where the iterator returns all the map keys ## Loops ### `break(), break(expr), continue(), continue(expr)` These allow to control execution of a loop either skipping current iteration code, using `continue`, or finishing the current loop, using `break`. `break` and `continue` can only be used inside `for`, `c_for`, `while`, `loop`, `map`, `filter`, `reduce` as well as Minecraft API block loops, `scan` and `volume` functions, while `break` can be used in `first` as well. Outside of the internal expressions of these functions, calling `break` or `continue` will cause an error. In case of the nested loops, and more complex setups, use custom `try` and `throw` setup. Please check corresponding loop function description what `continue` and `break` do in their contexts, but in general case, passed values to `break` and `continue` will be used in place of the return value of the internal iteration expression. ### `c_for(init, condition, increment, body)` `c_for` Mimics c-style tri-arg (plus body) for loops. Return value of `c_for` is number of iterations performed in the loop. Unlike other loops, the `body` is not provided with pre-initialized `_` style variables - all initialization and increments has to be handled by the programmers themselves. `break` and `continue` statements are handled within `body` expression only, and not in `condition` or `increment`.
c_for(x=0, x<10, x+=1,
c_for(y=0, y<10, y+=1,
print(str('%d * %d = %d', x, y, x*y))
)
)
### `for(list,expr(_,_i))`
Evaluates expression over list of items from the `list`. Supplies `_`(value) and `_i`(iteration number) to the `expr`.
Returns the number of times `expr` was successful. Uses `continue` and `break` argument in place of the returned
value from the `expr`(if supplied), to determine if the iteration was successful.
check_prime(n) -> !first( range(2, sqrt(n)+1), !(n % _) ); for(range(1000000,1100000),check_prime(_)) => 7216From which we can learn that there is 7216 primes between 1M and 1.1M ### `while(cond, limit, expr)` Evaluates expression `expr` repeatedly until condition `cond` becomes false, but not more than `limit` times. Returns the result of the last `expr` evaluation, or `null` if nothing was successful. Both `expr` and `cond` will recveived a bound variable `_` indicating current iteration, so its a number.
while(a<100,10,a=_*_) => 81 // loop exhausted via limit while(a<100,20,a=_*_) => 100 // loop stopped at condition, but a has already been assigned while(_*_<100,20,a=_*_) => 81 // loop stopped at condition, before a was assigned a value### `loop(num,expr(_),exit(_)?)` Evaluates expression `expr`, `num` number of times. code>expr receives `_` system variable indicating the iteration.
loop(5, game_tick()) => repeat tick 5 times list = l(); loop(5, x = _; loop(5, list += l(x, _) ) ); list // double loop, produces: [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], ... , [4, 2], [4, 3], [4, 4]]In this small example we will search for first 10 primes, apparently including 0:
check_prime(n) -> !first( range(2, sqrt(n)+1), !(n % _) ); primes = l(); loop(10000, if(check_prime(_), primes += _ ; if (length(primes) >= 10, break()))); primes // outputs: [0, 1, 2, 3, 5, 7, 11, 13, 17, 19]## Higher Order Functions ### `map(list,expr(_,_i))` Converts a `list` of values, to another list where each value is result of an expression `v = expr(_, _i)` where `_` is passed as each element of the list, and `_i` is the index of such element. If `break` is called the map returns whatever collected thus far. If `continue` and `break` are used with supplied argument, it is used in place of the resulting map element, otherwise current element is skipped.
map(range(10), _*_) => [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
map(players('*'), _+' is stoopid') [gnembon is stoopid, herobrine is stoopid]
### `filter(list,expr(_,_i))`
filters `list` elements returning only these that return positive result of the `expr`. With `break` and `continue`
statements, the supplied value can be used as a boolean check instead.
filter(range(100), !(_%5), _*_>1000) => [0, 5, 10, 15, 20, 25, 30]
map(filter(entity_list('*'),_=='Witch'), query(_,'pos') ) => [[1082.5, 57, 1243.5]]
### `first(list,expr(_,_i))`
Finds and returns the first item in the list that satisfies `expr`. It sets `_` for current element value,
and `_i` for index of that element. `break` can be called inside the iteration code, using its argument value
instead of the current item. `continue` has no sense and cannot be called inside `first` call.
first(range(1000,10000), n=_; !first( range(2, sqrt(n)+1), !(n % _) ) ) => 1009 // first prime after 1000Notice in the example above, that we needed to rename the outer `_` to be albe to use in in the inner `first` call ### `all(list,expr(_,_i))` Returns `true` if all elements on the list satisfy the condition. Its roughly equivalent to `all(list,expr) <=> for(list,expr)==length(list)`. `expr` also receives bound `_` and `_i` variables. `break` and `continue` have no sense and cannot be used inside of `expr` body.
all([1,2,3], check_prime(_)) => 1
all(neighbours(x,y,z), _=='stone') => 1 // if all neighbours of [x, y, z] are stone
map(filter(rect(0,4,0,1000,0,1000), l(x,y,z)=pos(_); all(rect(x,y,z,1,0,1),_=='bedrock') ), pos(_) )
=> [[-298, 4, -703], [-287, 4, -156], [-269, 4, 104], [242, 4, 250], [-159, 4, 335], [-208, 4, 416], [-510, 4, 546], [376, 4, 806]]
// find all 3x3 bedrock structures in the top bedrock layer
map( filter( rect(0,4,0,1000,1,1000,1000,0,1000), l(x,y,z)=pos(_);
all(rect(x,y,z,1,0,1),_=='bedrock') && for(rect(x,y-1,z,1,1,1,1,0,1),_=='bedrock')<8),
pos(_) ) => [[343, 3, -642], [153, 3, -285], [674, 3, 167], [-710, 3, 398]]
// ditto, but requiring at most 7 bedrock block in the 18 blocks below them
### `reduce(list,expr(_a,_,_i), initial)`
Applies `expr` for each element of the list and saves the result in `_a` accumulator. Consecutive calls to `expr`
can access that value to apply more values. You also need to specify the initial value to apply for the
accumulator. `break` can be used to terminate reduction prematurely. If a value is provided to `break` or `continue`,
it will be used from now on as a new value for the accumulator.
reduce([1,2,3,4],_a+_,0) => 10 reduce([1,2,3,4],_a*_,1) => 24