You may download a copy of Q'Nial from the Nial Systems web site
www.nial.com
.
For Windows there is both a console version and a programming environment.
For Linux there is a console version.
Follow the instructions given on the downloads page
Executable Downloads.
Open the directory c:\QNialv63. Double click on the ship icon with label winnial.exe . This starts the Q'Nial for Windows programming environment. In the Main Interpreter window, the prompt is 5 spaces. Enter an expression at the prompt and the display value appears starting at the left margin. The examples presented below can be entered and tested. To start the console version instead, click on cmd icon with label nial.exe
Start Q'Nial by typing: nial which starts the console Q'Nial environment. The prompt is 5 spaces. Enter an expression at the prompt and the display value appears starting at the left margin as shown in the examples below.
3 * 2
6
2+3
5
# Left to right precedence
3+5*4
32
# Assignment (:= or "gets")
A := 15*3
45
B gets A / 5
9.
# list assignment
X := 5 3 4 -2
5 3 4 -2
# element by element operations
X + X
10 6 8 -4
X * X
25 9 16 4
# scalar - list operations
3*X
15 9 12 -6
x / 3
1.66667 1. 1.33333 -0.666667
# reducing operations
sum X
10
prod X
-120
max X
5
# cross product
X OUTER* X
25 15 20 -10
15 9 12 -6
20 12 16 -8
-10 -6 -8 4
# generating data
Y := count 10
1 2 3 4 5 6 7 8 9 10
Z := random 3 5
0.487339 0.710791 0.265316 0.162762 0.537691
0.974659 0.0942834 0.620331 0.910949 0.326865
0.623449 0.315394 0.834813 0.699439 0.478038
# multiplication table
Y OUTER * Y
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
A := 4 6 reshape count 24
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
B := tell 4 6
+---+---+---+---+---+---+
|0 0|0 1|0 2|0 3|0 4|0 5|
+---+---+---+---+---+---+
|1 0|1 1|1 2|1 3|1 4|1 5|
+---+---+---+---+---+---+
|2 0|2 1|2 2|2 3|2 4|2 5|
+---+---+---+---+---+---+
|3 0|3 1|3 2|3 3|3 4|3 5|
+---+---+---+---+---+---+
# average of a list of numbers
average IS OPERATION A {
sum A / tally A }
average 30 40 60 80
52.5
# integers (32 bit integers)
357
357
-4
-4
# real numbers (double floating point numbers)
2.5
2.5
3e5
300000.
2.5e-3
0.0025
# Logical values (booleans) displayed as l and o
True
l
False
o
# Bit strings (boolean lists)
lollo
lollo
# Character, preceded by the left quote symbol:
`x
x
# String (character list) characters enclosed in single quotes:
'Hello, world!'
Hello, world!
# Phrase (or symbol) characters preceded by a double quote
"Hello
Hello
# or constructed from a string using operation phrase
phrase 'Hello, world!'
Hello, world!
# Faults (errors or special values) symbol preceded by question mark
??error
?error
# or constructed from a string using operation fault
fault '?bad syntax'
?bad syntax
# or result of invalid computation
27/0
?div
# list of integers
23 14 36
23 14 36
# round parentheses used for grouping
18 -2 (25 * 4) (27 - 13)
18 -2 100 14
# strand of characters is a string
`a `b `c
abc
`a `b `c = 'abc'
l
# strand of Booleans is a bitstring
True False True
lol
True False True = lol
l
# atomic types can be mixed
13 (25/4) "word
13 6.25 word
# items of lists can be lists - displayed with box diagrams
(3 4 5) (8 9 10) (11 12 13)
+-----+------+--------+
|3 4 5|8 9 10|11 12 13|
+-----+------+--------+
# can combine list notations
[3 4 5, 8 9 10, 11 12 13]
+-----+------+--------+
|3 4 5|8 9 10|11 12 13|
+-----+------+--------+
["apple, "pie] ["tastes, "great]
+---------+------------+
|apple pie|tastes great|
+---------+------------+
# can combine lists and atoms as items
[32,[87,"abc],True]
+--+------+-+
|32|87 abc|l|
+--+------+-+
# list items can have different lengths
[3 4, 8 9 10, 11 12 13 14]
+---+------+-----------+
|3 4|8 9 10|11 12 13 14|
+---+------+-----------+
# can have as many levels as needed
[3 4, 8 9 10, 11 12 13 14] 'abc'
+------------------------+---+
|+---+------+-----------+|abc|
||3 4|8 9 10|11 12 13 14|| |
|+---+------+-----------+| |
+------------------------+---+
# binary tree of integers stored as a nested list
[ [1, 2], [ [3, 4], 5] ]
+---+-------+
|1 2|+---+-+|
| ||3 4|5||
| |+---+-+|
+---+-------+
# generate integers using count and tell
tell 5
0 1 2 3 4
count 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# replicate an atom using reshape
5 reshape "word
word word word word word
# generate random real numbers between 0. and 1. using random
random 5
0.726391 0.448169 0.384064 0.961273 0.123186
# generate random permutation of 10 integers using random and gradeup
gradeup random 10
5 6 4 0 3 1 2 9 7 8
gradeup random 10
9 6 5 0 8 3 4 7 1 2
# operation list converts an atom to a 1-list
list 3
3
list 3 = 3
o
list 3 = [3]
l
# there is only one empty list - Null
Null = count 0
l
Null = tell 0
l
Null = ''
l
# a list is a 1-dimensional array
# a numeric list is called a vector in mathematics
# formed using reshape with a pair as the left argument
2 3 reshape 8 3 14 6 2 1
8 3 14
6 2 1
4 6 reshape count 24
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
# nested tables generated using count or tell
count 3 4
+---+---+---+---+
|1 1|1 2|1 3|1 4|
+---+---+---+---+
|2 1|2 2|2 3|2 4|
+---+---+---+---+
|3 1|3 2|3 3|3 4|
+---+---+---+---+
tell 2 3
+---+---+---+
|0 0|0 1|0 2|
+---+---+---+
|1 0|1 1|1 2|
+---+---+---+
# construct a table by using mix on a list of lists of same length
mix ['abcd','efgh']
abcd
efgh
mix [count 5,random 5]
1 2 3 4 5
0.819432 0.193461 0.498833 0.880408 0.00925989
# a numeric table is called a matrix in mathematics
# formed using reshape with a longer shape vector as left argument
3 4 5 reshape count 60
1 2 3 4 5 21 22 23 24 25 41 42 43 44 45
6 7 8 9 10 26 27 28 29 30 46 47 48 49 50
11 12 13 14 15 31 32 33 34 35 51 52 53 54 55
16 17 18 19 20 36 37 38 39 40 56 57 58 59 60
2 3 4 5 reshape count 120
1 2 3 4 5 21 22 23 24 25 41 42 43 44 45
6 7 8 9 10 26 27 28 29 30 46 47 48 49 50
11 12 13 14 15 31 32 33 34 35 51 52 53 54 55
16 17 18 19 20 36 37 38 39 40 56 57 58 59 60
61 62 63 64 65 81 82 83 84 85 101 102 103 104 105
66 67 68 69 70 86 87 88 89 90 106 107 108 109 110
71 72 73 74 75 91 92 93 94 95 111 112 113 114 115
76 77 78 79 80 96 97 98 99 100 116 117 118 119 120
# apply mix to a table of lists
mix count 3 4
1 1 2 1 3 1
1 2 2 2 3 2
1 3 2 3 3 3
1 4 2 4 3 4
# operations on atom-atom, atom-list, and list-list pairs
5 + 10
15
3* count 5
3 6 9 12 15
count 5 * 20 27 68 14 -3
20 54 204 56 -15
# atomic operations descend to all levels
20 + count 2 3
+-----+-----+-----+
|21 21|21 22|21 23|
+-----+-----+-----+
|22 21|22 22|22 23|
+-----+-----+-----+
[count 2 3] * [tell 2 3]
+-------------+
|+---+---+---+|
||0 0|0 2|0 6||
|+---+---+---+|
||2 0|2 2|2 6||
|+---+---+---+|
+-------------+
# arithmetic, logical, comparative, and scientific operations are distributed
lolloloo or llooolol
llllolol
lolloloo and llooolol
looooloo
exp 3 4 5
20.0855 54.5982 148.413
count 10 mod 3
1 2 0 1 2 0 1 2 0 1
count 10 quotient 3
0 0 1 1 1 2 2 2 3 3
# sizes must be equal, unless of length 1
count 5 + 2 3
?conform
[3 4 5, 6 7 8] + [7 8 9, 10 11 12 13]
+--------+--------+
|10 12 14|?conform|
+--------+--------+
[3 4 5, 6 7 8] + [7 8 9, 10]
+--------+--------+
|10 12 14|16 17 18|
+--------+--------+
# accumulative operations
sum count 20
210
prod count 6
720
max 3 5 -7 18 -4
18
min 3 5 -7 18 -4
-7
or llolool
l
and llolool
o
You have already learned of the structural operations reshape and mix.
Here are some others.
# rows - converts a table into a list of its rows
A := 4 6 reshape count 24
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
rows A
+-----------+--------------+-----------------+-----------------+
|1 2 3 4 5 6|7 8 9 10 11 12|13 14 15 16 17 18|19 20 21 22 23 24|
+-----------+--------------+-----------------+-----------------+
# cols - converts a table into a list of its columns
cols A
+---------+---------+---------+----------+----------+----------+
|1 7 13 19|2 8 14 20|3 9 15 21|4 10 16 22|5 11 17 23|6 12 18 24|
+---------+---------+---------+----------+----------+----------+
# flip - interchanges top two levels of an array
flip rows A
+---------+---------+---------+----------+----------+----------+
|1 7 13 19|2 8 14 20|3 9 15 21|4 10 16 22|5 11 17 23|6 12 18 24|
+---------+---------+---------+----------+----------+----------+
cols A = flip rows A
l
# transpose - transposes the rows and columns of a table
transpose A
1 7 13 19
2 8 14 20
3 9 15 21
4 10 16 22
5 11 17 23
6 12 18 24
# mix merges the top two levels of an array
mix rows A
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
mix cols A = transpose A
l
# reverse - reverses the items in an array
reverse count 10
10 9 8 7 6 5 4 3 2 1
reverse A
24 23 22 21 20 19
18 17 16 15 14 13
12 11 10 9 8 7
6 5 4 3 2 1
# rotate - rotates the items of an array
3 rotate count 10
4 5 6 7 8 9 10 1 2 3
-4 rotate count 10
7 8 9 10 1 2 3 4 5 6
# take - selects items from an array from the ends
4 take tell 7
0 1 2 3
-3 take count 7
5 6 7
3 4 take A
1 2 3 4
7 8 9 10
13 14 15 16
-3 -3 take A
10 11 12
16 17 18
22 23 24
# drop - selects items of an array after dropping some from the ends
3 drop tell 15
3 4 5 6 7 8 9 10 11 12 13 14
2 4 drop A
17 18
23 24
-2 1 drop A
2 3 4 5 6
8 9 10 11 12
# link - joins lists
count 5 link tell 10
1 2 3 4 5 0 1 2 3 4 5 6 7 8 9
# list - unwinds an array into its items
list A
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
list count 2 3
+---+---+---+---+---+---+
|1 1|1 2|1 3|2 1|2 2|2 3|
+---+---+---+---+---+---+
Nial has operations to measure the dimensionality, extents of dimensions and the
number of items in an array. These are: valence, shape and tally.
A := 4 6 reshape count 24
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
valence A
2
shape A
4 6
tally A
24
There are a number of operations that test array properties.
# testing if an array is atomic
atomic 54
l
atomic 4 5 6
o
# testing if an array is empty
empty Null
l
empty count 5
o
# selecting the unique items of an array
cull 23 14 2 5 3 2 8 14 -2 -3 1 -2
23 14 2 5 3 8 -2 -3 1
# selecting by bitstring pattern
lollol sublist count 6
1 3 4 6
A mod 3 match 0 sublist A
3 6 9 12 15 18 21 24
# defining an operation with one parameter
average IS OPERATION A { sum A / tally A }
average 4 17 23 18 45
21.4
# defining an operation with two parameter
upto IS OP M N { M + tell (N - M + 1) }
3 upto 7
3 4 5 6 7
# create a text file named examples.ndf with content:
# examples
# defining an operation with one parameter
average IS OPERATION A { sum A / tally A }
# defining an operation with two parameter
upto IS OP M N { M + tell (N - M + 1) }
# multiple parameters, multiple lines
foo is OP A B C D E {
X gets A + B + C;
D gets D * E;
X/D
}
# loaddefs - loads a script file, adds definitions to the workspace
loaddefs "examples l
# examples
# defining an operation with one parameter
average IS OPERATION A { sum A / tally A }
# defining an operation with two parameter
upto IS OP M N { M + tell (N - M + 1) }
# multiple parameters, multiple lines
foo is OP A B C D E {
X gets A + B + C;
D gets D * E;
X/D
}
# using: loaddefs "examples
# loads the script silently
# use foo
foo 3 4 5 6 7
0.285714
foo reverse 3 4 5 6 7
1.5
# see - displays a defined operation in canonical form
see "average
average IS OPERATION A {
+ A / tally A }
see "foo
foo IS OPERATION A B C D E {
X := A + B + C ;
D := D * E ;
X / D }
# all operations are monadic
+ 3 4
7
reshape 6 8
8 8 8 8 8 8
take -3 (count 5)
3 4 5
# all operations can be used prefix or infix - by rule A f B = f A B
3 sum 4
7
+ 3 4 5
12
# some operations require a pair as argument
reshape 4 5 6
?argument of reshape must be a pair
# infix uses are executed left-to-right
3*4+5
17
3+5*4
32
10 reshape 8 / 4
2. 2. 2. 2. 2. 2. 2. 2. 2. 2.
3 + 2 reshape 10 - 1
9 9 9 9 9
# sequence of prefix uses obey composition rule (f g) A = f g A = f (g A)
sum count reverse 2 3
12 9
sum count 2 3
9 12
# mixed infix prefix use obeys rule A f g B = A f (g B) = f A (g B)
2 tell sum 2 3
+---+---+---+---+---+
|0 0|0 1|0 2|0 3|0 4|
+---+---+---+---+---+
|1 0|1 1|1 2|1 3|1 4|
+---+---+---+---+---+
# special rule for defined operations with two or more parameters - argument must be
# a list that matches in length
foo 3 4 5
?op_parameter
23 foo 4 5 6
?op_parameter
upto 6
?op_parameter
The operation putfile writes a list of strings to a file in ascii form.
It places a newline indicator (CR-LF in Windows, newline in Linux) after
each string that is written.
"foobar putfile 'first line' 'second line'
The list can be in strand or bracket-comma notation or the value of a variable.
The operation getfile reads ascii characters from a file separating them into strings.
It removes the newline indicators between strings and returns a list of strings.
getfile "foobar
+----------+-----------+
|first line|second line|
+----------+-----------+
The operation appendfile appends one or more strings to an existing file.
"foobar appendfile 'third line' 'last line'
getfile "foobar
+----------+-----------+----------+---------+
|first line|second line|third line|last line|
+----------+-----------+----------+---------+
The form of an operation definintion is
opname IS OP parameters { expr-sequence }
which defines the operation opname.
Consider foo again
see "foo
foo IS OPERATION A B C D E {
X := A + B + C ;
D := D * E ;
X / D }
It has 5 formal parameters that are passed by value and a local variable X.
The body of the definnition consists of 3 expressions.
The first two assign expressions assign values to X and D.
The third expression computes X / D as the result of the operation.
When we use foo in the application
foo reverse 3 4 5 6 7
1.5
the argument to foo is the result of
reverse 3 4 5 6 7
7 6 5 4 3
The items of this list are bound to the parameters A, B, C, D and E respectively.
On execution,
X is assigned 7+6+5 = 18
D is assigned 4*3 = 12
and the result 18/12 = 1.5
is returned.
Nial provides second order functions called transformers that modify operations
to achieve specific effects.
For example, EACH modifies its argument function f so that
(EACH f) A applies f to the items of A.
A transformer is always used prefix and it is applied before the operation. Thus
EACH count 3 5 7
+-----+---------+-------------+
|1 2 3|1 2 3 4 5|1 2 3 4 5 6 7|
+-----+---------+-------------+
is the same as
(EACH f) count 3 5 7
+-----+---------+-------------+
|1 2 3|1 2 3 4 5|1 2 3 4 5 6 7|
+-----+---------+-------------+
A
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
(EACH sum) rows A
21 57 93 129
can be written
EACH sum rows A
21 57 93 129
Another example of a transformer is OUTER, where
A OUTER f B
applies f to each of the pairs formed from A and B.
4 5 OUTER * 2 7 9
8 28 36
10 35 45
Recursion works as expected in Nial
fact IS OP N { IF N = 0 THEN 1 ELSE N * fact (N - 1) ENDIF }
fact 6
720
Nial uses bracket-comma notation to represent a set of operations.
It forms an operation that applies each of the component operations to the
argument of the atlas to get a list result.
[3+, fact, 10*] 6
9 720 60
Like C, Nial has programming structures for conditional execution.
NIal also has loops, though programs usually run faster and are shorter if you avoid using them.
We discuss these features and the EACH transformers that often render loops unnecessary.
X := 5; Y := 7;
# conditional using statements
IF X < Y THEN
Sml := X; Lrg := Y;
ELSE
Sml := Y; Lrg := X;
ENDIF;
# conditional using expressions
Sml := IF X < Y THEN X ELSE Y ENDIF;
Lrg := IF X < Y THEN Y ELSE X ENDIF;
# using multiple assignments to do the test just once
X Y := 5 7;
Sml Lrg := IF X < Y THEN X Y ELSE Y X ENDIF;
Aside:
All expressions in Nial return a value, including assignments.
The value of an expression ending with ; is the fault ?noexpr
By convention this fault value is not displayed at the top level execution.
To see the fault enclose the result in a one-list.
[ (X := 5;) ]
?noexpr
# FOR loop
Use a FOR loop when you know the number of steps (definite iteration)
Total := 0;
FOR I WITH 10 20 30 40 DO
Total := Total + (Pi * I);
ENDFOR;
Total
314.159
# Can often achieve the effect of a FOR loop using an expression with an EACH transformer
sum EACH (Pi*) 10 20 30 40
314.159
# implicit loops are generally faster in Q'Nial
# WHILE loop
Use a WHILE loop when you don't know how many steps it will take (indefinite iteration)
# computer the series 1 + 1/(2*2) + 1/(3*3) + ... + (1/(N*N) to 5 decimal places
Term := 1;
I := 1;
Total := 0;
WHILE Term > 1e-5 DO
TOTAL := Total + Term;
I := I + 1;
Term := 1 / (I * I);
ENDWHILE;
Total I
1.64393 317
EACH modifies its operation argument to apply it to all the items
of the argument array. The result has the same shape as the argument
RULE: shape (EACH f A) = shape A
A gets 4 6 reshape count 24
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
EACH (2+) A
3 4 5 6 7 8
9 10 11 12 13 14
15 16 17 18 19 20
21 22 23 24 25 26
Two EACH applications can be combined.
RULE: (EACH f) (EACH g) A = EACH(f g) A
EACH exp EACH (2+) A
20.0855 54.5982 148.413 403.429 1096.63 2980.96
8103.08 22026.5 59874.1 162755. 442413. 1.2026e+06
3.26902e+06 8.88611e+06 2.4155e+07 6.566e+07 1.78482e+08 4.85165e+08
1.31882e+09 3.58491e+09 9.7448e+09 2.64891e+10 7.20049e+10 1.9573e+11
EACH (exp (2+)) A
20.0855 54.5982 148.413 403.429 1096.63 2980.96
8103.08 22026.5 59874.1 162755. 442413. 1.2026e+06
3.26902e+06 8.88611e+06 2.4155e+07 6.566e+07 1.78482e+08 4.85165e+08
1.31882e+09 3.58491e+09 9.7448e+09 2.64891e+10 7.20049e+10 1.9573e+11
A EACHLEFT f B applies f to pairs formed from the items of A and the argument B
3 4 5 EACHLEFT reshape "abc
+-----------+---------------+-------------------+
|abc abc abc|abc abc abc abc|abc abc abc abc abc|
+-----------+---------------+-------------------+
A EACHRIGHT f B applies f to pairs formed from the argument A and the items of B
3 4 EACHRIGHT reshape "abc "defg
+---------------+-------------------+
|abc abc abc abc|defg defg defg defg|
|abc abc abc abc|defg defg defg defg|
|abc abc abc abc|defg defg defg defg|
+---------------+-------------------+
A EACHBOTH f B applies f to pairs formed from the items of A and the items of B
3 4 EACHBOTH reshape "abc "defg
+-----------+-------------------+
|abc abc abc|defg defg defg defg|
+-----------+-------------------+
A OUTER f B computes applies f to the pairs formed from all combinations of
the items of A with the items of B
3 4 5 OUTER reshape 'abcd'
+-----+-----+-----+-----+
|aaa |bbb |ccc |ddd |
+-----+-----+-----+-----+
|aaaa |bbbb |cccc |dddd |
+-----+-----+-----+-----+
|aaaaa|bbbbb|ccccc|ddddd|
+-----+-----+-----+-----+
The same result can be obtained by
mix (A EACHLEFT EACHRIGHT f B)
mix (3 4 5 EACHLEFT EACHRIGHT reshape 'abcd')
+-----+-----+-----+-----+
|aaa |bbb |ccc |ddd |
+-----+-----+-----+-----+
|aaaa |bbbb |cccc |dddd |
+-----+-----+-----+-----+
|aaaaa|bbbbb|ccccc|ddddd|
+-----+-----+-----+-----+
The operation tell generates the 0-origin addresses for an array
with the shape of the argument.
tell 5
0 1 2 3 4
tell 4 6
+---+---+---+---+---+---+
|0 0|0 1|0 2|0 3|0 4|0 5|
+---+---+---+---+---+---+
|1 0|1 1|1 2|1 3|1 4|1 5|
+---+---+---+---+---+---+
|2 0|2 1|2 2|2 3|2 4|2 5|
+---+---+---+---+---+---+
|3 0|3 1|3 2|3 3|3 4|3 5|
+---+---+---+---+---+---+
The operation I pick A selects the item of A at address I.
3 pick 'abcdef'
d
X := 34 15 -2 35 798
34 15 -2 35 798
1 pick X
15
A := 4 6 reshape count 24
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
2 3 pick A
16
There is an indexing notation for selecting an item using A@I where A is a variable.
X@1
15
A@(2 3)
16
The operation I choose A selects the items of A at the addresses in I.
2 3 0 choose X
-2 35 34
[0 0, 1 1, 2 2, 3 3] choose A
1 8 15 22
There is an indexing notation for selecting multiple items using A#I where A is a variable.
X#(2 3 0)
-2 35 34
A#[0 0, 1 1, 2 2, 3 3]
1 8 15 22
For convenience there is also a notation for selecting a row or column from a table variable
A|[2,]
13 14 15 16 17 18
A|[,3]
4 10 16 22
B := rows A
+-----------+--------------+-----------------+-----------------+
|1 2 3 4 5 6|7 8 9 10 11 12|13 14 15 16 17 18|19 20 21 22 23 24|
+-----------+--------------+-----------------+-----------------+
2 4 reach B
17
There is an indexing notation for selecting along a pathusing A@@P where A is a variable
B@@(2 4)
17
The variable selection notations can also be used to insert an item or items into an array.
For example, to double the value at address 3 in X, use
X@3 := x@3 * 2
34 15 -2 70 798
To replace the diagonal items of A use
A#[0 0, 1 1, 2 2, 3 3] := 1000 2000 3000 4000
1000 2 3 4 5 6
7 2000 9 10 11 12
13 14 3000 16 17 18
19 20 21 4000 23 24
To negate the first row of A use
A|[0,] := opp A|[0,]
-1000 -2 -3 -4 -5 -6
7 2000 9 10 11 12
13 14 3000 16 17 18
19 20 21 4000 23 24
Nial represents scalars as numeric atoms, vectors as numeric lists,
and matrices as numeric tables.
We give some examples of linear algebra computations.
Larger examples can be tried by changing the value of N.
N := 4
4
# Scalar S
S := 3.14
3.14
# Vectors X, Y
X gets random N
0.633319 0.196128 0.329051 0.353133
Y gets random N
0.0997199 0.993036 0.956765 0.351386
# Matrices A and B
A gets random N N
0.740653 0.156837 0.95601 0.652851
0.470182 0.342205 0.44016 0.761598
0.18367 0.946969 0.71337 0.605643
0.0498337 0.554176 0.0283656 0.740685
B gets random N N
0.694195 0.340543 0.514273 0.388239
0.140726 0.177893 0.844948 0.0351305
0.438194 0.727605 0.858284 0.17794
0.63484 0.749474 0.416547 0.90947
# Scalar times Vector
S * X
1.98862 0.615843 1.03322 1.10884
# Vector addition
X + Y
0.733039 1.18916 1.28582 0.704518
# item-by-item vector multiplication
X * Y
0.0631546 0.194763 0.314824 0.124086
# Vector inner product
sum (X * Y)
0.696827
# Scalar times Matrix
S * A
2.32565 0.492468 3.00187 2.04995
1.47637 1.07452 1.3821 2.39142
0.576725 2.97348 2.23998 1.90172
0.156478 1.74011 0.089068 2.32575
# Matrix Vector multiplication
AX := EACH sum (rows A EACHLEFT * X)
1.04495 0.778671 0.750657 0.411144
# Matrix Matrix multiplication
AB := EACH sum (rows A OUTER * cols B)
1.3696 1.46502 1.60589 1.05692
1.05092 1.11205 1.22597 0.965537
0.957847 1.20397 1.75915 0.782327
0.595227 0.691318 0.826753 0.717494
# solve linear equations A x = y
A solve AX
0.633319 0.196128 0.329051 0.353133
X
0.633319 0.196128 0.329051 0.353133
Nial does not directly support relational data bases and SQL style queries and updates.
However, it is quite straightforward to build useful data tables and manipulate them.
Consider an application in which records for employees are managed.
These might be organized in a series of tables:
Table 1 - Employee numbers, Employee names, Social Security number
Table 2 - Employee numbers, Position, Department, Salary, Vacation allotment
Table 3 - Employee numbers, Employment status, Vacation days used
Table 4 - Employee numbers, Week number, Hours worked, Days missed for illness, vacation
etc.
Each table can be represented by a pair consisting of
a list of column names and a data structure holding the data for the table.
The data part can be organized in of three direct ways:
- as a Nial table T where each row is one entry in the table,
- as a nested list, rows T
- as a nested list, cols T
We choose the later representation for efficency of lookup and storage use.
# the data base tables
Tblnms := "EmpInfo "EmpPos "EmpData "WorkRecs
EmpInfo EmpPos EmpData WorkRecords
# list of column names for each table
EmpInfoCols := "EmpNo "EmpNm "EmpSin
EmpNo EmpNm EmpSin
EmpPosCols := "EmpNo "Posn "Dept "Sal "VacDays
EmpNo Posn Dept Sal VacDays
EmpRecCols := "EmpNo "Status "VacUsed
EmpNo Status VacUsed
WorkRecsCols := "EmpNo "WeekNo "Hours "SickDays "VacDays
EmpNo WeekNo Hours SickDays VacDays
# sample data for each table
EmpInfoData := flip
[100 'John Smith' 235648329,
201 'Pat Johnson' 384263549,
128 'Mary Armstrong' 653902194
]
+-----------+---------------------------------------+---------------------------
|100 201 128|+----------+-----------+--------------+|235648329 384263549 6539021
| ||John Smith|Pat Johnson|Mary Armstrong||
| |+----------+-----------+--------------+|
+-----------+---------------------------------------+---------------------------
--+
94|
|
|
--+
EmpPosData := flip
[100 "Pres "Admin 235000 30,
201 "Salesperson "Marketing 85000 20,
128 "AdminAsst "Marketing 45000 15
]
+-----------+--------------------------+-------------------------+--------------
|100 201 128|Pres Salesperson AdminAsst|Admin Marketing Marketing|235000 85000 4
+-----------+--------------------------+-------------------------+--------------
----+--------+
5000|30 20 15|
----+--------+
EmpRecData := flip
[100 "Active 3,
201 "Active 5,
128 "active 12
]
+-----------+--------------------+------+
|100 201 128|Active Active active|3 5 12|
+-----------+--------------------+------+
WorkRecsData := flip
[100 10 45 0 0,
201 10 35 0 2,
128 10 40 1 0,
100 11 45 0 0,
201 11 35 1 0,
128 11 40 1 1
]
+-----------------------+-----------------+-----------------+-----------+-------
|100 201 128 100 201 128|10 10 10 11 11 11|45 35 40 45 35 40|0 0 1 0 1 1|0 2 0 0
+-----------------------+-----------------+-----------------+-----------+-------
----+
0 1|
----+
# routine to display a table
displaytbl IS OP Nms Data {
mix flip (Nms EACHBOTH hitch Data) }
displaytbl WorkRecsCols WorkRecsData
EmpNo WeekNo Hours SickDays VacDays
100 10 45 0 0
201 10 35 0 2
128 10 40 1 0
100 11 45 0 0
201 11 35 1 0
128 11 40 1 1
# routine to select a single record in a table by Key (first column)
getrec IS OP Key Data {
Pos := Key find first Data;
Pos EACHRIGHT pick Data }
getrec 128 EmpInfoData
+---+--------------+---------+
|128|Mary Armstrong|653902194|
+---+--------------+---------+
# expression to get all entries in a table by Key
getrecs IS OP Key Data {
Posns := Key findall first Data;
Posns EACHLEFT EACHRIGHT pick Data }
getrecs 201 WorkRecsData
+-------------+-------------+
|201 10 35 0 2|201 11 35 1 0|
+-------------+-------------+
# routine to update a record in a data table
updateFld IS OP Tbl Key Fld Val {
TblCols TblDataNm := Tbl;
Data := value TblDataNm;
I := Key find first Data;
Fld_I := Fld find TblCols;
deepupdate TblDataNm [Fld_I,I] Val }
# assignment to update salary by employee name
updatesalary IS OP EmpName NewSalary {
Posn := EmpName find second EmpInfoData;
EmpNo := Posn pick first EmpInfoData;
updateFld (EmpPosCols "EmpPosData) EmpNo "Sal NewSalary; }
# table before update
displayTbl EmpPosCols EmpPosData
EmpNo Posn Dept Sal VacDays
100 Pres Admin 235000 30
201 Salesperson Marketing 85000 20
128 AdminAsst Marketing 45000 15
updatesalary 'Mary Armstrong' 48000;
# table after update
displayTbl EmpPosCols EmpPosData
EmpNo Posn Dept Sal VacDays
100 Pres Admin 235000 30
201 Salesperson Marketing 85000 20
128 AdminAsst Marketing 48000 15
One of the many advantages of interpretation is that
one can easily evaluate expressions that are constructed on the fly.
Choice := 2
2
Nms := 'W' 'X' 'Y' 'Z'
+-+-+-+-+
|W|X|Y|Z|
+-+-+-+-+
Arg := 5
5
Expr := link Nms@Choice ' := count ' (string Arg) ';'
Y := count 5;
execute Expr
Y
1 2 3 4 5
deleteblanks IS OP Str {
not (Str match ` ) sublist Str }
deleteblanks ' Where did all the flowers go. '
Wheredidalltheflowersgo.
# subset test
subset IS OPERATION A B { and ( A EACHLEFT in B ) }
'abc' subset 'qwertyckdsba'
l
# intersection
intersect IS OPERATION A B {
EACH and ( A EACHLEFT EACHRIGHT in A B ) sublist A
}
Friends := "Mary "Ludwig "Hercule "Tom "Sarah ;
Pals:= "Jack "Tony "Rick "Tom "Kalev;
Friends intersect Pals
Tom
Compute the moving average of length N for an array Data
moving_average IS OPERATION N Data {
Indicies := tell (tally Data - N + 1) EACHLEFT + tell N;
Groups := Indicies EACHLEFT choose Data;
EACH sum Groups / N }
2 moving_average 3 4 5 6 7 8
3.5 4.5 5.5 6.5 7.5
# This operation counts the number of occurrences in A of each value in
Values.
frequency IS OPERATION Values A {
EACH sum ( Values EACHLEFT EACHRIGHT = A ) }
frequency 'abc' 'The cat sat on the baseball bat'
5 3 1
# If the items of Values are know to be atomic then a faster version is:
atfrequency IS OPERATION Values A {
EACH sum ( Values EACHLEFT match A ) }
atfrequency 'abc' 'The cat sat on the baseball bat'
5 3 1
# use sieve algorithm, where candidates are removed when they are multiples
of primes already found.
# uses implicit loops except for controlling WHILE loop of indefinite length
sieve IS OPERATION N {
Candidates := rest count N;
Primes := Null;
WHILE not empty Candidates DO
Primes := Primes append first Candidates;
Candidates := not (Candidates mod first Candidates match 0)
sublist Candidates;
ENDWHILE;
Primes }
sieve 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
# count occurences in ranges
countinranges IS OP Vals RangeVals {
inrange IS OP V Rng {
V > first Rng and (V <= last Rng) };
Ranges := front Rangevals EACHBOTH pair rest Rangevals;
EACH sum (Vals EACHRIGHT EACHLEFT inrange Ranges) }
# 10 ranges of length 10
sieve 100 countinranges (10 * tell 11)
4 4 2 2 3 2 2 3 2 1
# 10 ranges of length 100
sieve 1000 countinranges (100 * tell 11)
25 21 16 16 17 14 16 14 15 14
# 10 ranges of length 1000
sieve 10000 countinranges (1000 * tell 11)
168 135 127 120 119 114 117 107 110 112
# 100 ranges of length 100
sieve 10000 countinranges (100 * tell 101)
25 21 16 16 17 14 16 14 15 14 16 12 15 11 17 12 15 12 12 13 14 10 15 15 10 11 15
14 12 11 12 10 11 15 11 14 13 12 11 11 15 9 16 9 11 12 12 12 8 15 12 11 10 10 1
3 13 12 10 16 7 12 11 13 15 8 11 10 12 12 13 9 10 11 9 11 15 12 10 10 10 11 10 1
4 9 8 12 13 11 13 9 11 12 11 11 15 7 13 11 12 9