Created Loop statement/expression (markdown)
242
Loop-statement-expression.md
Normal file
242
Loop-statement-expression.md
Normal file
@@ -0,0 +1,242 @@
|
||||
SMNP language provides a loop statement which also acts as expression.
|
||||
The statement has been totally designed from scratch and is not similar
|
||||
to any known loop statements from other languages at all.
|
||||
Loop allows you to repeat some instructions with counter set programmatically.
|
||||
All loops are created through loop operator (`^`).
|
||||
|
||||
# Simple loop
|
||||
The simplest loop consists only of counter, loop operator and instruction or block
|
||||
of instructions.
|
||||
|
||||
Example:
|
||||
```
|
||||
# the simplest loop
|
||||
3 ^ print("Money "); # Money Money Money
|
||||
|
||||
# the same using block of code
|
||||
|
||||
3 ^ {
|
||||
print("Money ");
|
||||
}
|
||||
|
||||
# Output: Money Money Money
|
||||
```
|
||||
|
||||
Of course, you can use any expression as counter, like variable or function call:
|
||||
```
|
||||
function provideCounter(x: int) {
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
provideCounter(5) ^ print("a"); # aaaaaaaaaa
|
||||
```
|
||||
|
||||
You can define a counter variable whose value is increased with each iteration
|
||||
using `as` clause (note, that values start from 0):
|
||||
```
|
||||
3 as i ^ print(i, " "); # 0 1 2
|
||||
```
|
||||
|
||||
# *while* loop
|
||||
You can create a loop which is controlled by logic condition.
|
||||
It can be done just putting a `bool` value as a counter.
|
||||
|
||||
Example:
|
||||
```
|
||||
end = false;
|
||||
i = 0;
|
||||
|
||||
not end ^ {
|
||||
if (i == 3) {
|
||||
end = true;
|
||||
}
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
println(end); # true
|
||||
println(i); # 4
|
||||
```
|
||||
|
||||
Note that condition-controlled loop doesn't support `as` clause.
|
||||
|
||||
# *For-each* loop
|
||||
This kind of loop works with lists, maps and strings.
|
||||
|
||||
## List
|
||||
You can put a list as a counter. In this case statement will be executed
|
||||
for each element of list. You can obtain access to element through `as` clause
|
||||
like in previous examples.
|
||||
|
||||
Example:
|
||||
```
|
||||
myList = [@c, @d, @e];
|
||||
|
||||
myList ^ print("Money "); # Money Money Money
|
||||
|
||||
myList as item ^ print(item, " "); # C D E
|
||||
```
|
||||
|
||||
You can put additional parameter into `as` clause. In this case the first parameter
|
||||
will be the value of passed list and the second one will be iterator that is increased after each loop iteration. If you are using more than one parameter in `as` clause,
|
||||
you have to enclose them between parentheses.
|
||||
|
||||
Example:
|
||||
```
|
||||
[@c, @d, @e] as (n, i) ^ println(i, ". ", n);
|
||||
|
||||
# Output:
|
||||
# 0. C
|
||||
# 1. D
|
||||
# 2. E
|
||||
```
|
||||
|
||||
## Map
|
||||
Map is also supported to act as a counter of loop.
|
||||
In this case statement will be executed for each value of passed map.
|
||||
|
||||
Example:
|
||||
```
|
||||
x = {
|
||||
a -> @c,
|
||||
b -> @d,
|
||||
c -> @e
|
||||
};
|
||||
|
||||
x ^ print("Money "); # Money Money Money
|
||||
```
|
||||
|
||||
You are also able to access keys and values of iterated map using parameters in `as` clause.
|
||||
You can use up to three parameters, where
|
||||
* the first is just a value
|
||||
* the second is a corresponding key
|
||||
* the third is an iterator increased by one with each iteration.
|
||||
|
||||
Example:
|
||||
```
|
||||
myMap = {
|
||||
first -> true,
|
||||
second -> [@c, @d, @e],
|
||||
third -> 14
|
||||
};
|
||||
|
||||
myMap as value ^ println(value);
|
||||
# Output:
|
||||
# true
|
||||
# [C, D, E]
|
||||
# 14
|
||||
|
||||
myMap as (value, key) ^ println(key, ": ", value);
|
||||
# Output:
|
||||
# first: true,
|
||||
# second: [C, D, E]
|
||||
# third: 14
|
||||
|
||||
myMap as (value, key, i) ^ println(i, ". ", key, ": ", value);
|
||||
# Output:
|
||||
# 0. first: true,
|
||||
# 1. second: [C, D, E]
|
||||
# 2. third: 14
|
||||
```
|
||||
|
||||
## String
|
||||
Loop operator supports also `string` counter. In this case, you are able to iterate through each character
|
||||
of passed string. As in the previous cases, you are able to access both current character and iterator using `as` clause.
|
||||
|
||||
Example:
|
||||
```
|
||||
text = "Hello";
|
||||
|
||||
text ^ print("0"); # 00000
|
||||
|
||||
text as char ^ println(char);
|
||||
# H
|
||||
# e
|
||||
# l
|
||||
# l
|
||||
# o
|
||||
|
||||
text as (char, index) ^ println(index, ". ", char);
|
||||
# 0. H
|
||||
# 1. e
|
||||
# 2. l
|
||||
# 3. l
|
||||
# 4. o
|
||||
```
|
||||
|
||||
# Filters
|
||||
Loops in SMNP language also support filtering.
|
||||
The filtering can be done with `%` clause, which contains a condition
|
||||
that must be met to execute iteration. `%` clause is placed at the very last
|
||||
of loop statement.
|
||||
|
||||
Example:
|
||||
```
|
||||
10 as i ^ println(i) % mod(i, 2) == 0;
|
||||
# Output:
|
||||
# 0
|
||||
# 2
|
||||
# 4
|
||||
# 6
|
||||
# 8
|
||||
```
|
||||
Filtering can be useful with simple counting loops like above, but it is really powerful with
|
||||
*for-each* loops. You can pass further only elements of list/map that met
|
||||
defined conditions.
|
||||
It is even more useful with special feature of loops that is covered in next section.
|
||||
|
||||
# Loop expression
|
||||
The power of designed loops relies on the fact, that all kinds of them actually can work as **expressions**.
|
||||
It means that you can use any kind of loop as e.g. function argument, because they can produce a value.
|
||||
They work similar to Python's list comprehension and actually produce a new list.
|
||||
One important condition you have to met in order to use loop as expression is to put
|
||||
expression as a loop's statement. Because of that in loop expression you can't use
|
||||
block of code. The statement must be a single instruction - expression.
|
||||
|
||||
Example:
|
||||
```
|
||||
x = [1, 2, 3, 4];
|
||||
|
||||
# 'y' holds numbers multipied by 2
|
||||
y = x as i ^ i * 2; # y = [2, 4, 6, 8]
|
||||
|
||||
# 'z' holds squares of even numbers
|
||||
z = x as i ^ i ** 2 % mod(i, 2) == 0; # y = [4.0, 16.0]
|
||||
```
|
||||
|
||||
Note, that loop statement is right associative.
|
||||
That means nested loop statements are being accumulated in right-hand branch.
|
||||
Take look at example:
|
||||
```
|
||||
2 ^ 4 ^ 6 ^ print("a");
|
||||
# is exactly the same as
|
||||
2 ^ (4 ^ (6 ^ print("a")));
|
||||
```
|
||||
is parsed to following abstract syntax tree:
|
||||
```
|
||||
^
|
||||
/ \
|
||||
2 ^
|
||||
/ \
|
||||
4 ^
|
||||
/ \
|
||||
6 print("a")
|
||||
```
|
||||
It could be a flaw if you would like to create a mapping chain using loop statements
|
||||
(like streams in Java 8 or LINQ in .NET), because it requires from operator
|
||||
to be left associative, so that first instruction would produce value and pass it further.
|
||||
It can be of course achieved with parentheses:
|
||||
```
|
||||
data = ["lorem", "ipsum", "dolor", "sit", "amet"];
|
||||
output = (((((data as d
|
||||
^ d
|
||||
% d.length > 3) as d
|
||||
^ d.length) as d
|
||||
^ d * 2) as d
|
||||
^ d + 1) as d
|
||||
^ d
|
||||
% d == 11);
|
||||
|
||||
println(output); # [11, 11, 11]
|
||||
```
|
||||
As you can see it actually works but is not convenient and readable.
|
||||
Reference in New Issue
Block a user