Python and Viv · Dicts and maps
Word frequency
What to notice
- A dict is
map()in Viv.m[k] = vstores andm[k]reads, andcounts.get(w, 0)isget(counts, w, 0). print(counts)writes the map as Python writes a dict,{'the': 4, 'cat': 1, ...}, and the keys stay in the order they were first stored, as a dict's do.w in countsis the same in both;counts.pop("and")isremove(counts, "and");list(counts)andcounts.values()arekeys(counts)andvalues(counts).- Sorting the words by count: Python's key is a tuple,
(-counts[w], w). Viv's keys are numbers or strings, so the Viv side sorts twice: by word, then by count withkey=fn(w) -> -counts[w], a stable sort that keeps the words of one count in order. - A map is a handle in Viv: a function that stores into a map it was given stores into the caller's map, as with a dict.
Python word_freq.py · 30 lines
Viv word_freq.viv · 36 lines
py2viv refuses word_freq.py
1 the text
4TEXT = "the cat sat on the mat and the dog sat on the log"
2TEXT = "the cat sat on the mat and the dog sat on the log"
py2viv refuses this program:
word_freq.py:20:29: not numeric Python: sorted of strings with key=
ranked = sorted(counts, key=lambda w: (-counts[w], w))
^^^^^^^^^^^^^^^^^^^^^^^^^
Sort by the strings themselves, or build (key, index) pairs of numbers and sort those.
word_freq.py:21:10: not numeric Python: iterating over a value of unknown type
for w in ranked[:TOP]:
^^^^^^^^^^^^
Loop over `range(len(a))` and index.
2 constructs outside the numeric subset (tools/py2viv/SUBSET.md) 2 count each word
7counts = {}
8for w in TEXT.split():
9 counts[w] = counts.get(w, 0) + 1
10print(counts)
5counts = map()
6for w in TEXT.split() {
7 counts[w] = get(counts, w, 0) + 1
8}
9print(counts)
(refused)
3 read the map
13print(len(counts), "distinct words")
14print("the:", counts["the"], " zebra:", counts.get("zebra", 0))
15for w in ["dog", "zebra"]:
16 print(w, "is a key" if w in counts else "is not a key")
12print(len(counts), "distinct words")
13print("the:", counts["the"], " zebra:", get(counts, "zebra", 0))
14for w in ["dog", "zebra"] {
15 print(w, "is a key" if w in counts else "is not a key")
16}
(refused)
4 the most frequent words
19TOP = 3
20ranked = sorted(counts, key=lambda w: (-counts[w], w))
21for w in ranked[:TOP]:
22 print(f"{w:>4} {counts[w]}")
19TOP = 3
20ranked = sorted(sorted(keys(counts)), key=fn(w) -> -counts[w])
21for w in ranked[:TOP] {
22 print(f"{w:>4} {counts[w]:d}")
23}
(refused)
5 remove a key
25n = counts.pop("and")
26print("removed and:", n, "left:", list(counts))
26n = remove(counts, "and")
27print("removed and:", n, "left:", keys(counts))
(refused)
6 checks
29assert counts["sat"] == 2
30assert sum(counts.values()) == len(TEXT.split()) - 1
30test "word counts" {
31 assert_true(counts["sat"] == 2)
32 assert_true(sum(values(counts)) == len(TEXT.split()) - 1)
33}
(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 word_freq.py
{'the': 4, 'cat': 1, 'sat': 2, 'on': 2, 'mat': 1, 'and': 1, 'dog': 1, 'log': 1}8 distinct wordsthe: 4 zebra: 0dog is a keyzebra is not a keythe 4on 2sat 2removed and: 1 left: ['the', 'cat', 'sat', 'on', 'mat', 'dog', 'log']
$ viv run word_freq.viv
{'the': 4, 'cat': 1, 'sat': 2, 'on': 2, 'mat': 1, 'and': 1, 'dog': 1, 'log': 1}8 distinct wordsthe: 4 zebra: 0dog is a keyzebra is not a keythe 4on 2sat 2removed and: 1 left: ['the', 'cat', 'sat', 'on', 'mat', 'dog', 'log']PASS word counts