Sequences

The for-loop in Minilang works with any value that can generate successive pairs of keys and values. Examples include strings, ranges, lists and maps. In some cases such as strings, ranges and lists, the keys will simply be the natural numbers, 1, 2, ..., etc. In other cases such as maps, the keys can be general values.

 1for K, V in ["A", "B", "C"] do
 2   print('{K} -> {V}\n')
 3end
 4
 5for K, V in 10 .. 12 do
 6   print('{K} -> {V}\n')
 7end
 8
 9for K, V in "cat" do
10   print('{K} -> {V}\n')
11end
12
13for K, V in {"a" is 1, "b" is 2, "c" is 3} do
14   print('{K} -> {V}\n')
15end
1 -> A
2 -> B
3 -> C

1 -> 10
2 -> 11
3 -> 12

1 -> c
2 -> a
3 -> t

a -> 1
b -> 2
c -> 3

Functions on Sequences

As well as iterating over a sequence with for-loop, Minilang provides a number of functions for working with sequences.

count(Sequence) returns the number of values generated by Sequence. count is defined simply as the method :count. The default implementation generates all the values from the sequence and counts but some sequence types (e.g. lists, maps, etc) can have more efficient implementations that don't require generating all the values.

list(Sequence) collects all the values generated by Sequence into a new list.

map(Sequence) collects all the keys and values generated by Sequence into a new map. Duplicate keys are replaced since maps only store one value per key.

1let C := count("cat")
2let L := list("cat")
3let M := map("cat")
4
5print('C = {C}\n')
6print('L = {L}\n')
7print('M = {M}\n')
C = 3
L = [c, a, t]
M = {1 is c, 2 is a, 3 is t}

Sequence Comprehensions

Sequences can be written in Minilang using comprehensions. Usually the resulting sequence will be used in a call to list, map, etc, but they are first class values that can be passed to other functions, stored in variables, etc.

1list(X + 1 for X in 1 .. 10)
2map(X to X:code for X in "cat")
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
{c is 99, a is 97, t is 116}

Chaining Sequences

Given an initial sequence, it is possible to create a new sequence by modifying the keys and/or values of the initial sequence, or by filtering out key-value pairs that satisfy a particular condition. There are a number of operators for doing this in Minilang:

1list("cat" -> :upper)
2
3fun is_consonant(L) not {"a", "e", "i", "o", "u"}[L:lower]
4
5list("cat" ->? is_consonant)
[C, A, T]
[c, t]

Generating Functions

Functions can behave as sequences by using the susp keyword to generate a value or key-value pair.

 1fun test(var N) do
 2   loop
 3      susp N
 4      if N = 1 then
 5         ret nil
 6      elseif 2 | N then
 7         N := old / 2
 8      else
 9         N := 3 * old + 1
10      end
11   end
12end
13
14for N in 1 .. 20 do
15   print('{N} -> {list(test(N))}\n')
16end
1 -> [1]
2 -> [2, 1]
3 -> [3, 10, 5, 16, 8, 4, 2, 1]
4 -> [4, 2, 1]
5 -> [5, 16, 8, 4, 2, 1]
6 -> [6, 3, 10, 5, 16, 8, 4, 2, 1]
7 -> [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
8 -> [8, 4, 2, 1]
9 -> [9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
10 -> [10, 5, 16, 8, 4, 2, 1]
11 -> [11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
12 -> [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
13 -> [13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
14 -> [14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
15 -> [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]
16 -> [16, 8, 4, 2, 1]
17 -> [17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
18 -> [18, 9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
19 -> [19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
20 -> [20, 10, 5, 16, 8, 4, 2, 1]

The susp keyword generates a key and value from a Minilang function. The function must return nil when it has no more values to produce. A key can be omitted, in which case nil is used as the key.