Python and Viv · Strings
Numbers from text
What to notice
floatandintread text as CPython does: surrounding spaces, exponents,inf, andint(s, 16)for another base. In Viv both give a double.- A dict of strings is a
map()in Viv;fields[key] = valueandf["temp"]read and write it as in Python. key, value = part.split("=")unpacks a two-element list in both. In Viv a list of another length stops the run with its line, as Python raisesValueError.names.append(x)isnames = append(names, x), and the empty[]becomes a list of strings or an array of numbers from what is appended to it.for name, t in zip(names, temps)is the same in both.- Python prints
float(" 2.5e-3 ")as0.0025; Viv'sprintwould write the same six digits here, but the Viv side usesfmtto match Python in general.
Python parse_numbers.py · 41 lines
Viv parse_numbers.viv · 49 lines
py2viv refuses parse_numbers.py
1 the input, one reading per line
4LOG = [
5 "station=north temp=21.5 rain=0",
6 "station=south temp=18.25 rain=12",
7 "station=east temp=-3.0 rain=4",
8 "# a comment line",
9 "station=west temp=1e1 rain=7",
10]
2LOG = [
3 "station=north temp=21.5 rain=0",
4 "station=south temp=18.25 rain=12",
5 "station=east temp=-3.0 rain=4",
6 "# a comment line",
7 "station=west temp=1e1 rain=7"
8]
py2viv refuses this program:
parse_numbers.py:16:22: not numeric Python: unpacking a list of strings (lifted by R5)
key, value = part.split("=")
^^^^^^^^^^^^^^^
Only several returned values, a vector (its rows for a matrix are not unpacked) and a shape unpack.
parse_numbers.py:28:18: not numeric Python: appending a value of unknown type to a list (lifted by R17)
names.append(f["station"])
^^^^^^^^^^^^
A list py2viv grows holds numbers, or rows of numbers (a new list, a copy, or a tuple).
parse_numbers.py:29:18: not numeric Python: appending a value of unknown type to a list (lifted by R17)
temps.append(float(f["temp"]))
^^^^^^^^^^^^^^^^
A list py2viv grows holds numbers, or rows of numbers (a new list, a copy, or a tuple).
3 constructs outside the numeric subset (tools/py2viv/SUBSET.md) 2 read the fields of one line
13def parse(line):
14 fields = {}
15 for part in line.split():
16 key, value = part.split("=")
17 fields[key] = value
18 return fields
11def parse(line) {
12 fields = map()
13 for part in line.split() {
14 key, value = part.split("=")
15 fields[key] = value
16 }
17 return fields
18}
(refused)
3 convert the numbers
21names = []
22temps = []
23total_rain = 0
24for line in LOG:
25 if line.startswith("#"):
26 continue
27 f = parse(line)
28 names.append(f["station"])
29 temps.append(float(f["temp"]))
30 total_rain += int(f["rain"])
21names = []
22temps = []
23total_rain = 0
24for line in LOG {
25 if line.startswith("#") {
26 continue
27 }
28 f = parse(line)
29 names = append(names, f["station"])
30 temps = append(temps, float(f["temp"]))
31 total_rain += int(f["rain"])
32}
(refused)
4 report
33for name, t in zip(names, temps):
34 print(f"{name:>6}: {t:6.2f}")
35print(f"mean temperature {sum(temps) / len(temps):.3f}")
36print(f"total rain {total_rain:d}")
37print(int("ff", 16), float(" 2.5e-3 "), float("inf"))
35for name, t in zip(names, temps) {
36 print(f"{name:>6}: {t:6.2f}")
37}
38print(f"mean temperature {sum(temps) / len(temps):.3f}")
39print(f"total rain {total_rain:d}")
40print(int("ff", 16), fmt(float(" 2.5e-3 ")), float("inf"))
(refused)
5 checks
40assert len(names) == 4
41assert temps[1] == 18.25
43test "parsed" {
44 assert_true(len(names) == 4)
45 assert_true(temps[1] == 18.25)
46}
(refused)
What they print
identical — the two programs print the same text.
Dimmed lines are left out of the comparison. Each Viv test block prints one PASS line; the Python checks the same facts with assert, which prints nothing.
$ python3 parse_numbers.py
north: 21.50south: 18.25east: -3.00west: 10.00mean temperature 11.688total rain 23255 0.0025 inf
$ viv run parse_numbers.viv
north: 21.50south: 18.25east: -3.00west: 10.00mean temperature 11.688total rain 23255 0.0025 infPASS parsed