diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2022-02-26 22:48:48 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2022-02-26 22:48:48 -0800 |
commit | 42526cb15d3cf5798b19e6063443a8260d8bd26f (patch) | |
tree | ce09317b498212519d24a4ae36c119dc0e77c09d /sieve.tlv | |
parent | 061e6a21a525fa857fc6f7405ed15b4a5d0a88aa (diff) | |
download | teliva-42526cb15d3cf5798b19e6063443a8260d8bd26f.tar.gz |
import https://github.com/majek/lua-channels
Also a little test program to demo channels in action.
Diffstat (limited to 'sieve.tlv')
-rw-r--r-- | sieve.tlv | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/sieve.tlv b/sieve.tlv new file mode 100644 index 0000000..13d1e8c --- /dev/null +++ b/sieve.tlv @@ -0,0 +1,409 @@ +# .tlv file generated by https://github.com/akkartik/teliva +# You may edit it if you are careful; however, you may see cryptic errors if you +# violate Teliva's assumptions. +# +# .tlv files are representations of Teliva programs. Teliva programs consist of +# sequences of definitions. Each definition is a table of key/value pairs. Keys +# and values are both strings. +# +# Lines in .tlv files always follow exactly one of the following forms: +# - comment lines at the top of the file starting with '#' at column 0 +# - beginnings of definitions starting with '- ' at column 0, followed by a +# key/value pair +# - key/value pairs consisting of ' ' at column 0, containing either a +# spaceless value on the same line, or a multi-line value +# - multiline values indented by more than 2 spaces, starting with a '>' +# +# If these constraints are violated, Teliva may unceremoniously crash. Please +# report bugs at http://akkartik.name/contact +- __teliva_timestamp: original + str_helpers: + >-- some string helpers from http://lua-users.org/wiki/StringIndexing + > + >-- index characters using [] + >getmetatable('').__index = function(str,i) + > if type(i) == 'number' then + > return string.sub(str,i,i) + > else + > return string[i] + > end + >end + > + >-- ranges using (), selected bytes using {} + >getmetatable('').__call = function(str,i,j) + > if type(i)~='table' then + > return string.sub(str,i,j) + > else + > local t={} + > for k,v in ipairs(i) do + > t[k]=string.sub(str,v,v) + > end + > return table.concat(t) + > end + >end + > + >-- iterate over an ordered sequence + >function q(x) + > if type(x) == 'string' then + > return x:gmatch('.') + > else + > return ipairs(x) + > end + >end + > + >-- insert within string + >function string.insert(str1, str2, pos) + > return str1:sub(1,pos)..str2..str1:sub(pos+1) + >end + > + >function string.remove(s, pos) + > return s:sub(1,pos-1)..s:sub(pos+1) + >end + > + >-- 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_eq: + >function check_eq(x, expected, msg) + > if eq(x, expected) then + > curses.addch('.') + > else + > print('F - '..msg) + > print(' expected '..str(expected)..' but got '..str(x)) + > teliva_num_test_failures = teliva_num_test_failures + 1 + > -- overlay first test failure on editors + > if teliva_first_failure == nil then + > teliva_first_failure = msg + > end + > end + >end +- __teliva_timestamp: original + eq: + >function eq(a, b) + > if type(a) ~= type(b) then return false end + > if type(a) == 'table' then + > if #a ~= #b then return false end + > for k, v in pairs(a) do + > if b[k] ~= v then + > return false + > end + > return true + > end + > end + > return a == b + >end +- __teliva_timestamp: original + str: + >-- smarter tostring + >-- slow; used only for debugging + >function str(x) + > if type(x) == 'table' then + > local result = '' + > result = result..#x..'{' + > for k, v in pairs(x) do + > result = result..str(k)..'='..str(v)..', ' + > end + > result = result..'}' + > return result + > end + > 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: + >-- only for arrays + >function filter(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: + >Mon Feb 21 17:45:04 2022 + sort_string: + >function sort_string(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_string(s) + > check_eq(sort_string(''), '', 'test_sort_string: empty') + > check_eq(sort_string('ba'), 'ab', 'test_sort_string: non-empty') + > check_eq(sort_string('abba'), 'aabb', 'test_sort_string: duplicates') + >end +- __teliva_timestamp: original + append: + >-- concatenate list 'elems' into 'l', modifying 'l' in the process + >function append(l, elems) + > for i=1,#elems do + > l[#l+1] = elems[i] + > end + >end +- __teliva_timestamp: original + window: + >window = curses.stdscr() +- __teliva_timestamp: original + render: + >function render(window) + > window:clear() + > -- draw stuff to screen here + > window:attron(curses.A_BOLD) + > window:mvaddstr(1, 5, "example app") + > window:attrset(curses.A_NORMAL) + > for i=0,15 do + > window:attrset(curses.color_pair(i)) + > window:mvaddstr(3+i, 5, "========================") + > end + > curses.refresh() + >end +- __teliva_timestamp: original + menu: + >-- To show app-specific hotkeys in the menu bar, add hotkey/command + >-- arrays of strings to the menu array. + >menu = {} +- __teliva_timestamp: original + update: + >function update(window) + > local key = curses.getch() + > -- process key here + >end +- __teliva_timestamp: original + init_colors: + >function init_colors() + > for i=0,7 do + > curses.init_pair(i, i, -1) + > end + > curses.init_pair(8, 7, 0) + > curses.init_pair(9, 7, 1) + > curses.init_pair(10, 7, 2) + > curses.init_pair(11, 7, 3) + > curses.init_pair(12, 7, 4) + > curses.init_pair(13, 7, 5) + > curses.init_pair(14, 7, 6) + > curses.init_pair(15, -1, 15) + >end +- __teliva_timestamp: original + main: + >function main() + > init_colors() + > + > while true do + > render(window) + > update(window) + > end + >end +- __teliva_timestamp: original + doc:blurb: + >To show a brief description of the app on the 'big picture' screen, put the text in a special buffer called 'doc:blurb'. + > + >You can also override the default big picture screen entirely by creating a buffer called 'doc:main'. +- __teliva_timestamp: + >Sat Feb 26 21:49:00 2022 + main: + >function main() + > task.spawn(main_task) + > task.scheduler() + > print('out of scheduler') + > curses.getch() + >end +- __teliva_timestamp: + >Sat Feb 26 21:50:11 2022 + main_task: + >function main_task() + > local c = task.Channel:new() + > task.spawn(counter, c) + > for i=1,10 do + > print(c:recv()) + > end + >end +- __teliva_timestamp: + >Sat Feb 26 21:50:11 2022 + __teliva_note: + >a simple counter + counter: + >function counter(c) + > local i = 2 + > while true do + > c:send(i) + > i = i+1 + > end + >end +- __teliva_timestamp: + >Sat Feb 26 21:54:53 2022 + filter_task: + >function filter_task(p, cin, cout) + > while true do + > local i = cin:recv() + > if i%p ~= 0 then + > cout:send(i) + > end + > end + >end +- __teliva_timestamp: + >Sat Feb 26 21:55:46 2022 + main_task: + >function main_task() + > local primes = task.Channel:new() + > task.spawn(sieve, primes) + > for i=1,10 do + > print(primes:recv()) + > end + >end +- __teliva_timestamp: + >Sat Feb 26 21:59:37 2022 + __teliva_note: + >filter out multiples of a single number + sieve: + >function sieve(ch) + > local iota = task.Channel:new() + > task.spawn(counter, iota) + > task.spawn(filter_task, 2, iota, ch) + >end +- __teliva_timestamp: + >Sat Feb 26 22:08:07 2022 + __teliva_note: + >implement the complete sieve algorithm + sieve: + >-- Set up a Sieve of Eratosthenes (https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) + >-- for computing prime numbers by chaining tasks, one per prime. + >-- Each task is responsible for filtering out all multiples of its prime. + >function sieve(primes_ch) + > local c = task.Channel:new() + > task.spawn(counter, c) + > while true do + > local p, newc = c:recv(), task.Channel:new() + > primes_ch:send(p) + > task.spawn(filter_task, p, c, newc) + > c = newc + > end + >end +- __teliva_timestamp: + >Sat Feb 26 22:09:47 2022 + main_task: + >function main_task(window) + > local primes = task.Channel:new() + > task.spawn(sieve, primes) + > while true do + > window:addstr(primes:recv()) + > window:addstr(' ') + > window:refresh() + > end + >end +- __teliva_timestamp: + >Sat Feb 26 22:08:52 2022 + __teliva_note: + >infinite primes + main: + >function main() + > window:nodelay(true) + > window:clear() + > task.spawn(main_task, window) + > task.scheduler() + > print('key pressed; done') + > window:nodelay(false) + > curses.getch() + >end +- __teliva_timestamp: + >Sat Feb 26 22:09:47 2022 + __teliva_note: + >clear screen when it fills up; pause on keypress + > + >In Teliva getch() implicitly refreshes the screen. + main_task: + >function main_task(window) + > local primes = task.Channel:new() + > task.spawn(sieve, primes) + > local h, w = window:getmaxyx() + > while true do + > window:addstr(primes:recv()) + > window:addstr(' ') + > local c = curses.getch() + > if c then break end -- key pressed + > local y, x = window:getyx() + > if y > h-1 then + > window:clear() + > end + > end + >end +- __teliva_timestamp: + >Sat Feb 26 22:27:25 2022 + doc:blurb: + >Sieve of Eratosthenes + >https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + > + >A demonstration of tasks and channels, the primitives for (cooperative) concurrency in Teliva. + > + >We string together a cascade of tasks connected by channels. Every prime number gets a new task that prints the first incoming number, and then filters out multiples of it from the incoming channel. + > + >This approach has the advantage that we don't need to create an array of n numbers to compute primes less than n. + > + >However, we still need to create p tasks and p channels if there are p primes less than n. Probably not worth it, given tasks and channels are much larger than numbers. This is just a demo. + > + >The noticeable periodic pauses are perhaps due to garbage collection. |