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