about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2022-03-19 16:59:30 -0700
committerKartik K. Agaram <vc@akkartik.com>2022-03-19 16:59:30 -0700
commitfddbe08fc896e09d0fec2773977341d72103ff90 (patch)
treedddd6d116c1acdf7df9a54688ee0cc15a579c6fd
parent7859317ece5477862e8924657298c3595dd8a8e9 (diff)
downloadteliva-fddbe08fc896e09d0fec2773977341d72103ff90.tar.gz
graphviz: for basic stats, show all nodes ordered
The ordering is topological; nodes come before their dependencies.

Also some more helpful functions in the template for new apps.
-rw-r--r--anagrams.tlv47
-rw-r--r--break.tlv47
-rw-r--r--gemini.tlv49
-rw-r--r--graphviz.tlv196
-rw-r--r--life.tlv47
-rw-r--r--lisp.tlv184
-rw-r--r--template.tlv47
-rw-r--r--toot-toot.tlv47
-rw-r--r--zet.tlv47
9 files changed, 527 insertions, 184 deletions
diff --git a/anagrams.tlv b/anagrams.tlv
index b4dd01d..b48d5c4 100644
--- a/anagrams.tlv
+++ b/anagrams.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
diff --git a/break.tlv b/break.tlv
index a34ee76..b57176f 100644
--- a/break.tlv
+++ b/break.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
diff --git a/gemini.tlv b/gemini.tlv
index e4fbb21..96a7b03 100644
--- a/gemini.tlv
+++ b/gemini.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
@@ -520,6 +567,8 @@
 - __teliva_timestamp: original
   main:
     >function main()
+    >  Window:clear()
+    >  Window:refresh()
     >  init_colors()
     >  local lines = {}
     >  local url = ''
diff --git a/graphviz.tlv b/graphviz.tlv
index a93d506..5d8594a 100644
--- a/graphviz.tlv
+++ b/graphviz.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
@@ -1112,3 +1159,152 @@
     >    window:addstr(' ')
     >  end
     >end
+- __teliva_timestamp:
+    >Sat Mar 19 09:19:10 2022
+  main:
+    >function main()
+    >  if #arg == 0 then
+    >    Window:clear()
+    >    print('restart this app with the name of a .dot file')
+    >    Window:refresh()
+    >    while true do Window:getch(); end
+    >  end
+    >  for _, filename in ipairs(arg) do
+    >    read_dot_file(filename, Graph)
+    >  end
+    >  Focus = sources(Graph)
+    >  Nodes = toposort(Graph)
+    >
+    >  while true do
+    >    render(Window)
+    >    update(Window)
+    >  end
+    >end
+- __teliva_timestamp:
+    >Sat Mar 19 09:32:33 2022
+  nodes:
+    >function nodes(graph)
+    >  local result = {}
+    >  for n, deps in pairs(graph) do
+    >    result[n] = true
+    >    for n, _ in pairs(deps) do
+    >      result[n] = true
+    >    end
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp:
+    >Sat Mar 19 16:27:32 2022
+  toposort:
+    >-- stable sort of nodes in a graph
+    >-- nodes always occur before all their dependencies
+    >-- disconnected nodes are in alphabetical order
+    >function toposort(graph)
+    >  -- non-map variables are arrays
+    >  -- result = leaves in graph
+    >  -- candidates = non-leaves
+    >  local result = {}
+    >  local resultMap = {}
+    >  local candidatesMap = nodes(graph)
+    >  local leavesMap = filter(candidatesMap, function(k, v) return graph[k] == nil end)
+    >  local leaves = to_array(leavesMap)
+    >  table.sort(leaves)
+    >  union(resultMap, leavesMap)
+    >  prepend(result, leaves)
+    >  subtract(candidatesMap, leavesMap)
+    >
+    >  function in_result(x, _) return resultMap[x] end
+    >  function all_deps_in_result(k, _) return all(graph[k], in_result) end
+    >  while true do
+    >    local oldcount = count(candidatesMap)
+    >    if oldcount == 0 then break end
+    >    local inducteesMap = filter(candidatesMap, all_deps_in_result)
+    >    local inductees = to_array(inducteesMap)
+    >    table.sort(inductees)
+    >    union(resultMap, inducteesMap)
+    >    prepend(result, inductees)
+    >    subtract(candidatesMap, inducteesMap)
+    >    if oldcount == count(candidatesMap) then
+    >      error('toposort: graph is not connected')
+    >    end
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp:
+    >Sat Mar 19 16:32:24 2022
+  render_focus:
+    >function render_focus(window)
+    >  local y, _ = window:getyx()
+    >  window:mvaddstr(y+1, 0, '')
+    >  bold(window, 'focus: ')
+    >  for _, node in ipairs(Focus) do
+    >    window:addstr(node)
+    >    window:addstr(' ')
+    >  end
+    >  y, _ = window:getyx()
+    >  window:mvaddstr(y+1, 0, '')
+    >  local lines, cols = window:getmaxyx()
+    >  for col=1,cols do
+    >    window:addstr('_')
+    >  end
+    >end
+- __teliva_timestamp:
+    >Sat Mar 19 16:33:19 2022
+  render_basic_stats:
+    >function render_basic_stats(window)
+    >  bold(window, tostring(#Nodes)..' nodes: ')
+    >  for i, node in ipairs(Nodes) do
+    >    window:attrset(curses.A_REVERSE)
+    >    window:addstr(i)
+    >    window:attrset(curses.A_NORMAL)
+    >    window:addstr(' ')
+    >    window:addstr(node)
+    >    window:addstr(' ')
+    >  end
+    >  local y, x = window:getyx()
+    >  window:mvaddstr(y+1, 0, '')
+    >  local lines, cols = window:getmaxyx()
+    >  for col=1,cols do
+    >    window:addstr('_')
+    >  end
+    >end
+- __teliva_timestamp:
+    >Sat Mar 19 16:35:34 2022
+  render_reachable_sets:
+    >function render_reachable_sets(window)
+    >  local deps = {}
+    >  local needed_by = {}
+    >  for _, node in ipairs(Focus) do
+    >    deps[node] = reachable(Graph, node)
+    >    for dep, _ in pairs(deps[node]) do
+    >      if needed_by[dep] == nil then
+    >        needed_by[dep] = {}
+    >      end
+    >      append(needed_by[dep], {node})
+    >    end
+    >  end
+    >  for k, v in ipairs(needed_by) do
+    >    table.sort(v)
+    >  end
+    >  local sets = {Focus}  -- queue
+    >  local done = {}
+    >  while #sets > 0 do
+    >    local from_nodes = table.remove(sets, 1)
+    >    if #from_nodes == 0 then break end
+    >    table.sort(from_nodes)
+    >    local key = table.concat(from_nodes)
+    >    if done[key] == nil then
+    >      done[key] = true
+    >      local y, x = window:getyx()
+    >      window:mvaddstr(y+2, 0, '')
+    >      window:attrset(curses.A_BOLD)
+    >      render_list(window, from_nodes)
+    >      window:attrset(curses.A_NORMAL)
+    >      window:addstr(' -> ')
+    >      render_set(window, filter(needed_by, function(node, users) return set_eq(users, from_nodes) end))
+    >      for i, elem in ipairs(from_nodes) do
+    >        table.insert(sets, all_but(from_nodes, i))
+    >      end
+    >    end
+    >  end
+    >end
diff --git a/life.tlv b/life.tlv
index 4445de8..e35fd59 100644
--- a/life.tlv
+++ b/life.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
diff --git a/lisp.tlv b/lisp.tlv
index 894995e..a064adf 100644
--- a/lisp.tlv
+++ b/lisp.tlv
@@ -66,21 +66,6 @@
     >
     >-- TODO: backport utf-8 support from Lua 5.3
 - __teliva_timestamp: original
-  debugy:
-    >debugy = 5
-- __teliva_timestamp: original
-  dbg:
-    >-- helper for debug by print; overlay debug information towards the right
-    >-- reset debugy every time you refresh screen
-    >function dbg(window, s)
-    >  local oldy = 0
-    >  local oldx = 0
-    >  oldy, oldx = window:getyx()
-    >  window:mvaddstr(debugy, 60, s)
-    >  debugy = debugy+1
-    >  window:mvaddstr(oldy, oldx, '')
-    >end
-- __teliva_timestamp: original
   check:
     >function check(x, msg)
     >  if x then
@@ -149,175 +134,6 @@
     >  return tostring(x)
     >end
 - __teliva_timestamp: original
-  map:
-    >-- only for arrays
-    >function map(l, f)
-    >  result = {}
-    >  for _, x in ipairs(l) do
-    >    table.insert(result, f(x))
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  reduce:
-    >-- only for arrays
-    >function reduce(l, f, init)
-    >  result = init
-    >  for _, x in ipairs(l) do
-    >    result = f(result, x)
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  filter:
-    >function filter(h, f)
-    >  result = {}
-    >  for k, v in pairs(h) do
-    >    if f(k, v) then
-    >      result[k] = v
-    >    end
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  ifilter:
-    >-- only for arrays
-    >function ifilter(l, f)
-    >  result = {}
-    >  for _, x in ipairs(l) do
-    >    if f(x) then
-    >      table.insert(result, x)
-    >    end
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  find_index:
-    >function find_index(arr, x)
-    >  for n, y in ipairs(arr) do
-    >    if x == y then
-    >      return n
-    >    end
-    >  end
-    >end
-- __teliva_timestamp: original
-  trim:
-    >function trim(s)
-    >  return s:gsub('^%s*', ''):gsub('%s*$', '')
-    >end
-- __teliva_timestamp: original
-  split:
-    >function split(s, d)
-    >  result = {}
-    >  for match in (s..d):gmatch("(.-)"..d) do
-    >    table.insert(result, match);
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  sort_letters:
-    >function sort_letters(s)
-    >  tmp = {}
-    >  for i=1,#s do
-    >    table.insert(tmp, s[i])
-    >  end
-    >  table.sort(tmp)
-    >  local result = ''
-    >  for _, c in pairs(tmp) do
-    >    result = result..c
-    >  end
-    >  return result
-    >end
-    >
-    >function test_sort_letters(s)
-    >  check_eq(sort_letters(''), '', 'test_sort_letters: empty')
-    >  check_eq(sort_letters('ba'), 'ab', 'test_sort_letters: non-empty')
-    >  check_eq(sort_letters('abba'), 'aabb', 'test_sort_letters: duplicates')
-    >end
-- __teliva_timestamp: original
-  count_letters:
-    >function count_letters(s)
-    >  local result = {}
-    >  for i=1,s:len() do
-    >    local c = s[i]
-    >    if result[c] == nil then
-    >      result[c] = 1
-    >    else
-    >      result[c] = result[c] + 1
-    >    end
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  append:
-    >-- concatenate list 'elems' into 'l', modifying 'l' in the process
-    >function append(l, elems)
-    >  for i=1,#elems do
-    >    table.insert(l, elems[i])
-    >  end
-    >end
-- __teliva_timestamp: original
-  all_but:
-    >function all_but(x, idx)
-    >  if type(x) == 'table' then
-    >    local result = {}
-    >    for i, elem in ipairs(x) do
-    >      if i ~= idx then
-    >        table.insert(result,elem)
-    >      end
-    >    end
-    >    return result
-    >  elseif type(x) == 'string' then
-    >    if idx < 1 then return x:sub(1) end
-    >    return x:sub(1, idx-1) .. x:sub(idx+1)
-    >  else
-    >    error('all_but: unsupported type '..type(x))
-    >  end
-    >end
-    >
-    >function test_all_but()
-    >  check_eq(all_but('', 0), '', 'all_but: empty')
-    >  check_eq(all_but('abc', 0), 'abc', 'all_but: invalid low index')
-    >  check_eq(all_but('abc', 4), 'abc', 'all_but: invalid high index')
-    >  check_eq(all_but('abc', 1), 'bc', 'all_but: first index')
-    >  check_eq(all_but('abc', 3), 'ab', 'all_but: final index')
-    >  check_eq(all_but('abc', 2), 'ac', 'all_but: middle index')
-    >end
-- __teliva_timestamp: original
-  set:
-    >function set(l)
-    >  local result = {}
-    >  for i, elem in ipairs(l) do
-    >    result[elem] = true
-    >  end
-    >  return result
-    >end
-- __teliva_timestamp: original
-  set_eq:
-    >function set_eq(l1, l2)
-    >  return eq(set(l1), set(l2))
-    >end
-    >
-    >function test_set_eq()
-    >  check(set_eq({1}, {1}), 'set_eq: identical')
-    >  check(not set_eq({1, 2}, {1, 3}), 'set_eq: different')
-    >  check(set_eq({1, 2}, {2, 1}), 'set_eq: order')
-    >  check(set_eq({1, 2, 2}, {2, 1}), 'set_eq: duplicates')
-    >end
-- __teliva_timestamp: original
-  clear:
-    >function clear(lines)
-    >  while #lines > 0 do
-    >    table.remove(lines)
-    >  end
-    >end
-- __teliva_timestamp: original
-  zap:
-    >function zap(target, src)
-    >  clear(target)
-    >  append(target, src)
-    >end
-- __teliva_timestamp: original
   menu:
     >-- To show app-specific hotkeys in the menu bar, add hotkey/command
     >-- arrays of strings to the menu array.
diff --git a/template.tlv b/template.tlv
index 49d35ed..c82d274 100644
--- a/template.tlv
+++ b/template.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
diff --git a/toot-toot.tlv b/toot-toot.tlv
index 0590202..b03d209 100644
--- a/toot-toot.tlv
+++ b/toot-toot.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then
diff --git a/zet.tlv b/zet.tlv
index 3864f51..b3d1c90 100644
--- a/zet.tlv
+++ b/zet.tlv
@@ -249,6 +249,45 @@
     >  return result
     >end
 - __teliva_timestamp: original
+  union:
+    >function union(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = v
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  subtract:
+    >-- set subtraction
+    >function subtract(a, b)
+    >  for k, v in pairs(b) do
+    >    a[k] = nil
+    >  end
+    >  return a
+    >end
+- __teliva_timestamp: original
+  all:
+    >-- universal quantifier on sets
+    >function all(s, f)
+    >  for k, v in pairs(s) do
+    >    if not f(k, v) then
+    >      return false
+    >    end
+    >  end
+    >  return true
+    >end
+- __teliva_timestamp: original
+  to_array:
+    >-- turn a set into an array
+    >-- drops values
+    >function to_array(h)
+    >  local result = {}
+    >  for k, _ in pairs(h) do
+    >    table.insert(result, k)
+    >  end
+    >  return result
+    >end
+- __teliva_timestamp: original
   append:
     >-- concatenate list 'elems' into 'l', modifying 'l' in the process
     >function append(l, elems)
@@ -257,6 +296,14 @@
     >  end
     >end
 - __teliva_timestamp: original
+  prepend:
+    >-- concatenate list 'elems' into the start of 'l', modifying 'l' in the process
+    >function prepend(l, elems)
+    >  for i=1,#elems do
+    >    table.insert(l, i, elems[i])
+    >  end
+    >end
+- __teliva_timestamp: original
   all_but:
     >function all_but(x, idx)
     >  if type(x) == 'table' then