The kcats Programming Language Lexicon
Table of Contents
- 1. Standard library source and documentation
- 1.1. Comparison
- 1.2. Stack Ops
- 1.3. Program execution
- 1.4. Collections
- 1.5. Dictionary modules
- 1.6. Math
- 1.7. Serialization
- 1.8. Boolean logic
- 1.9. Byte encoding and decoding
- 1.10. Strings
- 1.11. Error handling
- 1.12. Methods
- 1.13. Database
- 1.14. Pipes
- 1.15. Crypto
- 1.16. Time and date
- 1.17. Nested Environments
- 1.18. TODO Functional environment
- 2. Issues
1. Standard library source and documentation
1.1. Comparison
Words that help compare one item to another, with concepts of equal
, greater
, less
etc.
[= [[spec [[item item] [boolean]]] [examples [[[1 2 =] [[]] "Different Numbers are not equal"] [[1 1 =] [yes] "Same numbers are equal"] [[1 1.0 =] [yes] "Same value integer and float are equal"] [[[1] [] =] [[]] "Number and Nothing are unequal"] [[[1 [[]]] [1 [[]]] =] [yes] "Same nested list with numbers are equal"] [[[1.0 ["foo"]] [1.0 ["foo"]] =] [yes] "Same nested list with string are equal"] [["hi" "hi" =] [yes] "Same strings are equal"] [["hi" "there" =] [[]] "Different strings are unequal"] [[\h \h =] [yes] "Same characters are equal"] [[\h \i =] [[]] "Different characters are unequal"] [["hi" encode "hi" encode =] [yes] "Same bytes are equal"] [["hi" encode "there" encode =] [[]] "Different bytes are unequal"] [[[] yes =] [[]] "Different booleans unequal"] [[[1.0 ["foo"]] [1.0 ["bar"]] =] [[]] "Nested lists with different strings are unequal"] [[[] [] =] [yes] "'Nothing' is equal to itself"] [[[] [] association =] [yes] "List/Association empty container types are equal"] [[[] [] set =] [yes] "List/Set empty container types are equal"] [[[[a b]] [[a b]] association =] [[]] "Nonempty List/Association types are unequal"] [[[1 2 3] set [3 1 2] set =] [yes] "Sets constructed from different lists are equal"]]]]] [compare [[spec [[item item] [word]]] [examples [[["a" "b" compare] [[less] unwrap] "string lexicographical order with single character inequality"] [["a" "a" compare] [[equal] unwrap] "string lexicographical order with single character equality"] [[1 1 compare] [[equal] unwrap] "Same integer compares equal"] [[2 1 compare] [[greater] unwrap] "Integer order inequality"] [[1 [foo] unwrap compare] [[less] unwrap] "Integer/list order inequality"] [[1 "foo" encode compare] [[less] unwrap] "Integer/byte order inequality"] [[[foo] unwrap "foo" encode compare] [[less] unwrap] "Word/string order inequality"] [["foo" encode "foo" compare] [[less] unwrap] "String order equaltiy"] [[[] [[]] unwrap compare] [[equal] unwrap] "Unwrapped Nothing value equality"] [[[] [1] rest compare] [[equal] unwrap] "Nothing/emptied container equality"]]]]] ;; TODO these should be in terms of compare and not limited to numbers [< [[spec [[number number] [boolean]]] [examples [[[1 2 <] [yes] "Integer is less"] [[2.2 1.1 <] [[]] "Float is not less"] [[1 2.2 <] [yes] "Integer/float is less"] [[1.1 1.1 <] [[]] "Equal floats is not less"]]]]] [> [[spec [[number number] [boolean]]] [examples [[[2 1 >] [yes] "Integer is greater"] [[1.1 2.2 >] [[]] "Float is not greater"] [[2.2 1 >] [yes] "Integer/float is greater"] [[1.1 1.1 >] [[]] "Equal floats is not greater"]]]]] [<= [[spec [[number number] [boolean]]] [examples [[[1 2 <=] [yes] "Integer is less/equal"] [[2.2 1.1 <=] [[]] "Float is not less/equal"] [[1 2.2 <=] [yes] "Integer/float is less/equal"] [[1.1 1.1 <=] [yes] "Equal floats is less/equal"]]]]] [>= [[spec [[number number] [boolean]]] [examples [[[2 1 >=] [yes] "Integer is greater/equal"] [[1.1 2.2 >=] [[]] "Float is not greater/equal"] [[2.2 1 >=] [yes] "Integer/float is greater/equal"] [[1.1 1.1 >=] [yes] "Equal floats is greater/equal"]]]]]
[min [[spec [[number number] [number]]] [definition [[<] [] [swap] if drop]] [examples [[[2 3 min] [2] "Smaller of two positive integers"] [[-5 -3 min] [-5] "Smaller of two negative integers"] [[0.3 0.2 min] [0.2] "Smaller of two floats <1"]]]]] [max [[spec [[number number] [number]]] [definition [[>] [] [swap] if drop]] [examples [[[2 3 max] [3] "Larger of two positive integers"] [[-5 -3 max] [-3] "Larger of two positive integers"] [[0.3 0.2 max] [0.3] "Larger of two floats <1"]]]]]
1.2. Stack Ops
[drop [[spec [[item] []]] [examples [[[1 2 3 drop] [1 2] "Drop integer on ToS"] [[1 2 3 [a b c] drop] [1 2 3] "Drop list on ToS"]]]]] [clone [[spec [[[item a]] [[item a] [item a]]]] [examples [[[1 2 3 clone] [1 2 3 3] "Clone integer on ToS"]]]]] [evert [[spec [[list] [list *]]] [examples [[[1 2 3 [4 5 6] evert] [6 5 4 [3 2 1]] "Evert a list of integers with the stack"]]]]]
[clonedown [[spec [[[item a] [item b]] [[item a] [item b] [item b]]]] [definition [swap clone float]] [examples [[[1 2 3 clonedown] [1 2 2 3] "Clone the 2nd item on the stack"]]]]] [clonedeep [[spec [[[item a] [item b] [item c]] [[item a] [item b] [item c] [item c]]]] [definition [[clonedown] dip]] [examples [[[1 2 3 4 clonedeep] [1 2 2 3 4] "Clone the 3rd item on the stack"]]]]] [over [[spec [[[item a] [item b]] [[item b] [item a] [item b]]]] [definition [clonedown swap]] [examples [[[1 2 3 over] [1 2 3 2] "Copy the 2nd item to ToS"]]]]] [under [[spec [[[item a] [item b]] [[item a] [item b] [item a]]]] [definition [clone sink]] [examples [[[1 2 3 under] [1 3 2 3] "Copy the ToS to the 2nd item"]]]]] [dropdown [[spec [[[item a] [item b]] [[item b]]]] [definition [swap drop]] [examples [[[1 2 3 dropdown] [1 3] "Drop the 2nd item"]]]]] [dropdeep [[spec [[[item a] [item b] [item c]] [[item a] [item b]]]] [definition [float drop]] [examples [[[1 2 3 dropdeep] [2 3] "Drop the 3rd item"]]]]] [snapshot [[spec [[] [list]]] [doc "Save the whole stack as a list on the stack"] [definition [[] evert clone evert unwrap]] [examples [[[1 2 3 snapshot] [1 2 3 [3 2 1]] "Copy the stack to ToS"] [[snapshot] [[]] "Copy stack to ToS when stack is empty"]]]]] [restore [[spec [[list] [*]]] [definition [evert drop]] [examples [[["x" "y" [1 2 3] restore] [3 2 1] "Replace stack with list"] [[[] restore] [] "Replace stack with empty list"]]]]]
1.2.1. Motion
These words change the order of items on the stack.
[swap [[spec [[[item a] [item b]] [[item b] [item a]]]] [examples [[[1 2 3 swap] [1 3 2] "Swap top two items"]]]]] [swapdown [[spec [[[item a] [item b] [item c]] [[item a] [item c] [item b]]]] [examples [[[1 2 3 swapdown] [2 1 3] "Swap 2nd and 3rd items"]]]]] [float [[spec [[[item a] [item b] [item c]] [[item c] [item a] [item b]]]] [examples [[[1 2 3 float] [2 3 1] "Move 3rd item to ToS"]]]]] [sink [[spec [[[item a] [item b] [item c]] [[item b] [item c] [item a]]]] [examples [[[1 2 3 sink] [3 1 2] "Move ToS to 3rd item"]]]]]
[flip [[spec [[[item a] [item b] [item c]] [[item c] [item b] [item a]]]] [definition [float swapdown]] [examples [[[1 2 3 flip] [3 2 1] "Swap ToS and 3rd item"]]]]]
1.3. Program execution
[execute [[spec [[program] [*]]] [examples [[[[1 2 +] execute] [3] "Execute a program"] [[1 2 [] execute] [1 2] "Execute an empty program"] [[1 2 [[+] execute] execute] [3] "Nested execution"]]]]] [branch [[spec [[[program no-branch] [program yes-branch] [item condition]] [*]]] [examples [[[5 yes [3 *] [4 +] branch] [15] "Branch on true condition"] [[6 [] [3 *] [4 +] branch] [10] "Branch on false condition"]]]]] [recur [[spec [[[program rec2] [program rec1] [program yes-branch] [program pred]] [*]]] [examples [[[3 [1 <=] [] [clone dec] [execute *] recur] [6] "Recur with reduction"]]]]] [loop [[spec [[program [item flag]] [*]]] [examples [[[10 yes [-2 * clone 50 <] loop] [160] "Looping"] [[10 [] [-2 * clone 50 <] loop] [10] "Looping with false initial condition is no-op"]]]]] [dip [[spec [[program [item a]] [[item a] *]]] [examples [[[1 8 [inc] dip] [2 8] "Dipping a program under ToS"] [[1 2 [dec] unwrap [+] dip] [3 [dec] unwrap] "A bare word on stack is left intact and not executed"]]]]] ;; TODO: This depends on `if` so might need to move elsewhere, maybe Methods? [decide [[spec [[[list test-expr-pairs]] [*]]] [doc "Takes a list of choices (pairs of test, program) and executes the first program whose test passes. if none pass, returns 'nothing'. Stack is reset between testing conditions."] [examples [[[5 [[[3 =] ["three"]] [[5 =] ["five"]] [[7 =] ["seven"]] [[yes] ["something else"]]] decide] [5 "five"] "Decide with matching condition"] [[9 [[[3 =] ["three"]] [[5 =] ["five"]] [[7 =] ["seven"]] [[yes] ["something else"]]] decide] [9 "something else"] "Decide with matching default condition"] [[9 [[[3 =] ["three"]] [[5 =] ["five"]] [[7 =] ["seven"]]] decide] [9 []] "Decide with no matching condition"]]]]]
[decorate [[spec [[list program] [program]]] [definition [[[wrap] dip put] step]] [examples [[[[1 inc] [foo bar] decorate] [[[[1 inc] foo] bar]] "Decorate a program with a series of modifiers"]]]]] [decorated [[spec [[list program] [*]]] [definition [decorate execute]] [examples [[[1 2 [+] [bail shield] decorated] [1 2 3] "Execute a decorated program"]]]]] ;; TODO: implement as axiom (which would depend on 'restore' which should also be axiom?) [shield [[spec [[program] [item]]] [doc "Runs program keeping top of stack produced but protects existing items from being consumed."] [definition [[snapshot] dip inject first]] [examples [[[1 2 3 [=] shield] [1 2 3 []] "Execute a program shielding the stack from consumption"]]]]] [shielddown [[spec [[program item] [item]]] [definition [shield dropdown]] [examples [[[1 2 3 [=] shielddown] [1 2 []] "Execute a program consuming only the original ToS"]]]]] [shielddeep [[spec [[[program p] [item consumed] [item consumed]] [[item result]]]] [definition [shield [drop drop] dip]] [examples [[[1 2 3 [+ +] shielddeep] [1 6] "Execute a program consuming only the original top 2 items"]]]]] [if [[spec [[[program no-branch] [program yes-branch] [program condition]] [*]]] [definition [[shield] dipdown branch]] [examples [[[5 [5 =] [3 *] [4 +] if] [15] "Conditional with true predicate"] [[6 [5 =] [3 *] [4 +] if] [10] "Conditional with false predicate"]]]]] [when [[spec [[[program yes-branch] [program condition]] [*]]] [definition [[] if]] [examples [[[3 [odd?] [inc] when] [4] "Conditional with no false branch and true predicate"] [[3 [even?] [inc] when] [3] "Conditional with no false branch and false predicate"]]]]] ;; TODO: drop dependency on 'decorated' [dipdown [[spec [[program [item a] [item b]] [[item a] [item b] *]]] [definition [[dip dip] decorated]] [examples [[[1 2 3 [inc] dipdown] [2 2 3] "Dip program under top two items"]]]]] [dipdeep [[spec [[program [item a] [item b] [item c]] [[item a] [item b] [item c] *]]] [definition [[dipdown dip] decorated]] [examples [[[1 2 3 4 [inc] dipdeep] [2 2 3 4] "Dip program under top 3 items"]]]]] [dive [[spec [[program [item a]] [item [item a] *]]] [definition [dip swap]] [examples [[[4 5 6 [+] dive] [6 9] "Dip program and move result to ToS"]]]]] [divedown [[spec [[program [item a] [item b]] [item [item a] [item b] *]]] [definition [dipdown float]] [examples [[[5 6 7 8 [+] divedown] [7 8 11] "Dip under top 2 items and move result to ToS"]]]]] [divedeep [[spec [[program [item a] [item b] [item c]] [item [item a] [item b] [item c] *]]] [definition [wrap [divedown] join dip swap]] [examples [[[4 5 6 7 8 [+] divedeep] [6 7 8 9] "Dip under top 3 items and move result to ToS"]]]]] [inject [[spec [[program list] [list]]] [doc "Inject the quoted program into the list below it (runs the program with the list as its stack). Does not affect the rest of the stack."] [definition [swap evert take dip evert]] [examples [[[1 2 3 [4 5 6] [* +] inject] [1 2 3 [26]] "Inject program into list as if it's the stack"]]]]] [while [[spec [[[program body] [program pred]] [*]]] [definition [swap [shield] decorate ;; add shield to the pred program clone dipdown ;; run it on the previous ToS join loop]] [examples [[[3 [0 >] [clone dec] while] [3 2 1 0] "While loop"]]]]] [until [[spec [[[program body] [program pred]] [*]]] [definition [swap ;; pred body [not] join ;; reverse logic [shield] decorate ;; add shield to the pred program -> pred body join ;; [body .. pred] yes swap ;; run at least once loop]] [examples [[[2 [even?] [inc] until] [4] "Until loop"]]]]] [times [[spec [[[integer howmany] [program body]] [*]]] [definition [swap [dec] swap put [dip] join ;; build [dec body dip] [0 >] swap while drop]] [examples [[[[5] 3 times] [5 5 5] "Can create an item multiple times"] [[[5] 0 times] [] "0 times is a no-op"] [[1 1 [inc swap] 3 times] [3 2] "Can run a program multiple times"]]]]] [primrec [[spec [[[program rec1] [program exit] [number repetitions]] [*]]] [definition [[execute] swap join ;; add execute to rec1 to be recurs rec2 [[drop] swap join] dip ;; add drop to exit condition [[zero?]] dipdown ;; put the condition on bottom [[clone dec]] dip ;; add the r1 recur]] ;; now its generic recur [examples [[[5 [1] [*] primrec] [120] "Simple countup loop"]]]]] [bail [[spec [[program] [*]]] [definition [[swap] [execute] [drop] if]] [examples [[[[] [inc] bail] [[]] "Can bail on invalid input"] [[1 [inc] bail] [2] "Valid input doesn't bail"]]]]]
1.4. Collections
[join [[spec [[sized sized] [sized]]] [examples [[[["a" "b"] ["c" "d"] join] [["a" "b" "c" "d"]] "Join two collections of strings"] [["ab" "cd" join] ["abcd"] "Join two strings"] [["ab" encode "cd" encode join "abcd" encode =] [yes] "Two joined byte seqs are equal to the combined literal"] [[[[a b] [c d]] association [[e f] [a g]] join] [[[a g] [c d] [e f]] association] "Joining list+assoc -> assoc, 2nd arg keys take priority"] [[[[e f] [a g]] [[a b] [c d]] association join] [[[a b] [e f] [c d]] association] "Joining assoc+list -> assoc, 2nd arg keys take priority"] [[[a b c d] set [a e] join] [[a b c d e] set] "Join set with list -> set"] [[[a e] [a b c d] set join] [[a b c d e] set] "Join list with set -> set"] [["" "" join] [""] "Join two empty strings -> empty string"] [["" [1 2 3] join] [[1 2 3]] "Join empty string + list -> list (identity)"] [["a" [\b \c] join] ["abc"] "Join a string with a list of chars -> string"] [[[\b \c] "a" join] ["bca"] "Join a list of chars with string -> string"] [["" [\b \c] join] ["bc"] "Join an empty string with list of chars -> string"] [["abc" [\d \e 12] join] [[\a \b \c \d \e 12]] "Join a string with list -> list"] [["abc" [] join] ["abc"] "Join a string with empty list -> string"] [["" [] join] [""] "Join empty string with empty list -> string"] [[[1 2 3] set [4 4 4] join] [[1 2 3 4] set] "Join set with list -> set"]]]]] [put [[spec [[item receptacle] [receptacle]]] [examples [[[[] 1 put] [[1]] "Put integer into empty list"] [[[1 2 3] 4 put] [[1 2 3 4]] "Put integer into list"] [["foo" \d put] ["food"] "Put character into string"] [["foo" encode 32 put string] ["foo "] "Put byte into byte array"]]]]] [count [[spec [[sized] [number]]] [examples [[[["a" "b" "cd"] count] [3] "Count list of strings"] [["abcd" count] [4] "Count chars in string"] [["abcd" encode count] [4] "Count bytes in byte array"] [[[[a b] [c d]] association count] [2] "Count entries in association"]]]]] [second [[spec [[ordered] [item]]] [examples [[[[4 5 6] second] [5] "Get second item of list"] [["foo" second [\o]] "Get second item of string"] [[[] second] [[]] "Get second item of empty list -> Nothing"]]]]] [last [[spec [[ordered] [item]]] [examples [[[[3 4 5 6] last] [6] "Get last item of list"] [["foo" last [\o]] "Get last item of string"] [[[] last] [[]] "Get last item of empty list -> Nothing"]]]]] [step [[spec [[program dispenser] [*]]] [examples [[[1 [2 3 4] [*] step] [24] "Step through numbers doing arithmetic"] [[1 [] [*] step] [1] "Stepping through empty list is no-op"]]]]] [take [[spec [[dispenser] [item dispenser]]] [examples [[[["a" "b" "c"] take] [["b" "c"] "a"] "Take a string from a list"] [[[1 2 3] take] [[2 3] 1] "Take a number from a list"] [[[[a "foo"] [b "foo"] [c "foo"]] take dropdown second] ["foo"] "Take an entry from association is nondeterministic"] [[[1 3 5 7 9] set take dropdown odd?] [yes] "Take item from set is nondeterministic"]]]]] [pop [[spec [[ordered] [item ordered]]] [examples [[[["a" "b" "c"] pop] [["a" "b"] "c"] "Pop last string from list"] [[[1 2 3] pop] [[1 2] 3] "Pop last number from list"]]]]] [wrap [[spec [[item] [list]]] [examples [[[1 wrap] [[1]] "Wrap a number"] [[[1 2] wrap] [[[1 2]]] "Wrap a list"]]]]] [unwrap [[spec [[list] [*]]] [examples [[[[1] unwrap] [1] "Unwrap a list of one item"] [[[] unwrap] [] "Unwrap an empty list is a no-op"] [[[1 2 3] unwrap] [1 2 3] "Unwrap a list of multiple items"]]]]] [reverse [[spec [[ordered] [ordered]]] [examples [[[[1 2 3] reverse] [[3 2 1]] "Reverse a list"] [["123" reverse] ["321"] "Reverse a string"]]]]] [slice [[spec [[integer integer ordered] [ordered]]] [examples [[["foobar" 0 3 slice] ["foo"] "Slice a string with valid indices"] [["foobar" 0 7 slice] [[]] "Slice a string with index past end -> Nothing"] [["foobar" encode 0 3 slice] ["foo" encode] "Slice a byte array with valid indices"] [[[a b c d e] 0 3 slice] [[a b c]] "Slice a list with valid indices"]]]]] [cut [[spec [[integer sized] [list]]] [definition [[[[[count] dive] shield slice] [0 swap slice]] [execute] map [drop drop] dip unwrap]] [examples [[["abcdefghijklmnopqrstuvwxyz" 5 cut] ["fghijklmnopqrstuvwxyz" "abcde"] "Cut string at index"]]]]] [empty [[spec [[sized] [sized]]] [examples [[["foo" empty] [""] "Create empty container from string"] [["foo" encode empty] ["" encode] "Create empty container from byte array"] [[[1 2 3] empty] [[]] "Create empty container from list"] [[[[a b] [c d]] association empty] [[] association] "Create empty container from association"] [[[1 2 3] set empty] [[] set] "Create empty container from set"]]]]] [range [[spec [[integer integer integer] [list]]] [examples [[[1 5 1 range] [[1 2 3 4]] "Create integer range with step of 1"] [[3 13 3 range] [[3 6 9 12]] "Create integer range with step greater than 1"]]]]] [empty? [[spec [[item] [boolean]]] [examples [[[[] empty?] [yes] "Empty list is empty"] [[1 empty?] [[]] "Number is not empty"] [["" empty?] [yes] "Empty string is empty"] [[[foo] empty?] [[]] "Non-empty list is not empty"]]]]] [pad [[spec [[[item padding] [integer newsize] sized] [sized]]] [definition [[[[count] shield] dive -] dip swap repeat swap join]] [examples [[[[1 2 3] 5 0 pad] [[0 0 1 2 3]] "Pad a list at front, to given size"] [[[1 2 3 4 5 6] 5 0 pad] [[1 2 3 4 5 6]] "Padding a list to smaller than original size is a no-op"]]]]] [list? [[spec [[item] [boolean]]] [examples [[[[1] list?] [yes] "A list is a list"] [[[] list?] [yes] "An empty list is a list"] [[5 list?] [[]] "A number is not a list"] [["foo" list?] [[]] "A string is not a list"] [[[] association list?] [[]] "An empty association is not a list"]]]]] [sort-indexed [[spec [[sized] [sized]]] [examples [[[[[1 1] [3 3] [2 2]] sort-indexed] [[1 2 3]] "Sorting a list of key-value pairs by key"]]]]] [pack [[spec [[[list template]] [list]]] [examples [[["x" [foo] [bar] unwrap [*2 [*1 x **2] c d 1 2 3] pack] ["x" [[foo] [bar x foo] c d 1 2 3]] "Packing values from the stack, into a template"]]]]]
[something? [[spec [[item] [boolean]]] [definition [empty? not]] [examples [[[1 something?] [yes] "A number is something"] [[[] something?] [[]] "Empty list is not something"] [["" something?] [[]] "Empty string is not something"]]]]] [first [[spec [[ordered] [item]]] [definition [take dropdown]] [examples [[[[4 5 6] first] [4] "Get the first item of a list"] [["foo" first] [\f] "The first item of a string is the first character"] [[[] first] [[]] "The first item of an empty list is Nothing"]]]]] [rest [[spec [[sized] [sized]]] [definition [take drop]] [examples [[[[1 2 3] rest] [[2 3]] "Take rest of list"] [["foo" rest] ["oo"] "Take rest of string"]]]]] [butlast [[spec [[sized] [sized]]] [definition [pop drop]] [examples [[[[1 2 3] butlast] [[1 2]] "Take all but last of list"]]]]] [prepend [[spec [[item sized] [sized]]] [definition [wrap swap join]] [examples [[[[1 2] 3 prepend] [[3 1 2]] "Prepend to list"] [["oo" \f prepend] ["foo"] "Prepend to string"]]]]] [every? [[spec [[program sized] [boolean]]] [definition [[swap] [[take] dip clone [float [shielddown] dive] dive [] [drop every?] [dropdown dropdown] if] [drop drop yes] if]] [examples [[[[2 4 6] [even?] every?] [yes] "Every number matches predicate"] [[[2 4 5] [even?] every?] [[]] "Not every number matches predicate"] [[[] [[]] every?] [yes] "Every item in empty list matches any predicate"] [[[2 4 6] [] every?] [yes] "Every item in list matches empty predicate"] [[11 [2 4 6] [+ odd?] every?] [11 yes] "Stack is shielded from predicate"] [[12 [[even?] [positive?] [3 mod 0 =]] [execute] every?] [12 yes] "Can check list of predicates with execute predicate"]]]]] [any? [[spec [[program sized] boolean]] [definition [[swap] [[take] dip clone [float [shielddown] dive] dive [] [dropdown dropdown] [drop any?] if] [drop drop []] if]] [examples [[[[2 4 6] [even?] any?] [yes] "Any number matches predicate"] [[[3 5 7] [even?] any?] [[]] "No number matches predicate"] [[[] [yes] any?] [[]] "No item in empty list matches any predicate"] [[[[] 2 4 6] [] any?] [2] "Empty predicate returns first truthy item"] [[11 [3 5 6] [+ odd?] any?] [11 yes] "Stack is shielded from predicate"] [[-15 [[even?] [positive?] [3 mod 0 =]] [execute] any?] [-15 yes] "Can check list of predicates with execute predicate"]]]]] [map [[spec [[program sized] [list]]] [definition [[] sink ;; put empty results below list [swap [*1 shielddown] dip swap put] pack step]] [examples [[[[1 2 3] [inc] map] [[2 3 4]] "Pass each item through a program"] [[1 [1 2 3] [+] map] [1 [2 3 4]] "Program has access to rest of stack"] [[7 9 [1 2 3] [+ *] map] [7 9 [70 77 84]] "Stack is shielded from mapping program"] [[7 9 [1 2 3] [drop drop] map] [7 9 [7 7 7]] "Result of program can be lower stack items"] [[7 9 [+] [] map] [7 9 [+]] "Empty program is a no-op"]]]]] [filter [[spec [[program sized] [list]]] [definition [[] sink ;; put empty results below list [swap [*1 shield] dip swap [] [drop swap put] [drop dropdown] if] pack step]] [examples [[[[1 2 3] [odd?] filter] [[1 3]] "Filter a list with predicate"] [[[2 4 6] [odd?] filter] [[]] "Filter with predicate that matches no items"] [[33 [1 2 3] [33 + odd?] filter] [33 [2]] "Filter predicate uses existing stack items"]]]]] [sort [[spec [[program sized] [list]]] [definition [[clone **1 pair] pack map sort-indexed]] [examples [[[[1 3 2] [] sort] [[1 2 3]] "Sort a list of numbers"] [[["Carol" "Alice" "bob"] [] sort] [["Alice" "Bob" "Carol"]] "Sort a list of strings"] [[["Charlie" "Alice" "bob"] [count] sort] [["Bob" "Alice" "Charlie"]] "Sort list of strings by length"]]]]] [repeat [[spec [[[integer howmany] item] [list]]] [definition [[] sink [wrap [put] join] dip times]] [examples [[["hi" 3 repeat] [["hi" "hi" "hi"]] "Create a list of repeated items"]]]]] [indexed [[spec [[list] [list]]] [definition [[count] shield [0] dip 1 range swap zip]] [examples [[[[a b c] indexed] [[[0 a] [1 b] [2 c]]] "Index a list"]]]]] [indexer [[spec [[] [program]]] [definition [0 [[generate] dive [[pair] shielddown [inc] dip] bail]]] [examples [[[[a b c] [indexer] assemble] [[[0 a] [1 b] [2 c]]] "Index a generator"]]]]] [indexof [[spec [[item list] [item]]] [definition [[indexer] dip ;; use wrap so we can find index of words, ;; otherwise the word gets executed [second wrap =] swap wrap put [[swapdown] dip] inject keep generate first]] [examples [[[[[a b c] [take] [c] unwrap indexof] shield] [2] "Get the index of first matching item"] [[[[a b c] [take] [d] unwrap indexof] shield] [[]] "No matching item -> Nothing"] [[[[a b c d c e] [take] [c] unwrap indexof] shield] [2] "Multiple matches returns index of first match"]]]]] [interpose [[spec [[item ordered] [ordered]]] [definition [[] flip [swap pair join [pop] shield] step drop pop drop]] [examples [[[[foo bar baz] "hi" interpose] [[foo "hi" bar "hi" baz]] "Interpose string between words"] [[[] "hi" interpose] [[]] "Empty list is a no-op"] [[[foo] "hi" interpose] [[foo]] "Single item list is a no-op"]]]]] [starts? [[spec [[[ordered prefix] [ordered target]] [boolean]]] [definition [[[zip [unwrap =] every?] ;; the items at matching indexes are equal [[count] both >=]] ;; the prefix is shorter than the target [execute] every? dropdown dropdown]] ;; drop the originals [examples [[["abcd" "ab" starts?] [yes] "String starts with matching string"] [["abcd" "" starts?] [yes] "String starts with empty string"] [["" "ab" starts?] [[]] "Empty string doesn't start with a string"] [["abcd" "bb" starts?] [[]] "String doesn't start with non-matching string"] [[[1 2 3 4] [1 2] starts?] [yes] "List starts with matching list"]]]]] [ends? [[spec [[ordered ordered] [boolean]]] [definition [[reverse] both starts?]] [examples [[["abcd" "cd" ends?] [yes] "String ends with matching string"] [["abcd" "" ends?] [yes] "String ends with empty string"] [["abcd" "bb" ends?] [[]] "String doesn't end with non-matching string"] [[[1 2 3 4] [3 4] ends?] [yes] "List ends with matching list"]]]]] [pair [[spec [[item item] [list]]] [definition [[wrap] dip put]] [examples [[[1 2 pair] [[1 2]] "Pair up two numbers into a list"] [[["hi"] ["there" "foo"] pair] [[["hi"] ["there" "foo"]]] "Pair up two lists into a new list"]]]]] [pair? [[spec [[item] [boolean]]] [definition [[count 2 =] [drop drop []] recover]] [examples [[["ab" pair?] [yes] "2-character string is a pair"] [[[a b] pair?] [yes] "2-item list is a pair"] [["abc" pair?] [[]] "3-character string is not a pair"] [[[] pair?] [[]] "Nothing is not a pair"] [[7 pair?] [[]] "Number is not a pair"]]]]] [triplet [[spec [[item item] [list]]] [definition [[pair] dip put]] [examples [[[1 2 3 triplet] [[1 2 3]] "Make a 3-item list from 3 stack items"] [[["hi"] ["there" "foo"] ["bar"] triplet] [[["hi"] ["there" "foo"] ["bar"]]] "Make a 3-item list from smaller lists"]]]]] [both? [[spec [[program item item] [boolean]]] [definition [sink pair swap every?]] [examples [[[1 2 [odd?] both?] [[]] "Test two items for predicate when not all match"] [[1 3 [odd?] both?] [yes] "Test two items for predicate when all match"]]]]] [both [[spec [[program [item a] [item b]] [item item]]] [definition [[pair] dip step]] [examples [[[1 2 [inc] both] [2 3] "Run program on two stack items"]]]]] [walk [[spec [[[program item-transform] list] [list]]] [definition [[list? not] swap [[] swap] [[join] join step wrap] recur unwrap]] [examples [[[[1 2 [3 [4 5] 6]] [inc wrap] walk] [[2 3 [4 [5 6] 7]]] "Walk a nested list"] [[[1 2 [3 [4 5] 6]] [clone inc pair] walk] [[1 2 2 3 [3 4 [4 5 5 6] 6 7]]] "Walk a nested list and splice results"]]]]] ; [template [[spec [[[list template]] [list]]] ; [definition [[snapshot ; ;; build a map of word like *1, *2 etc to values on the stack ; ;; Do a separate entry for **1, **2, etc which means to splice the value ; [count] shield inc 1 1 swapdown range ; ["*" "**"] [swap [string join word] map] map ; unwrap join dropdown ; [clone [wrap] map swap join] dip swap zip association] dive ; ;; save copy of template ; [clone] dive ; [[swap get] swap prepend wrap ; [shield ; [] [dropdown] [drop wrap] if] join ; walk] dip ; ;; find the highest index placeholder ; flatten set 0 swap ; [[word?] ; ;; try to parse as a placeholder and get the index ; [string ["*" starts?] [take drop] while ; [number max] [drop drop] recover] ; [drop] if] step ; ;; drop that many items from the stack ; [drop] swap float [times] dip]] ; [examples [[["x" [foo] [bar] unwrap ; [*2 [*1 x **2] c d 1 2 3] template] ; ["x" [[foo] [bar x foo] c d 1 2 3] ]]]]]] [flatten [[spec [[list] [list]]] [definition [[] swap [list? not] [put] [] [step] recur]] [examples [[[[a b [c [d e] f] g] flatten] [[a b c d e f g]] "Flatten a nested list"]]]]]
1.4.1. Associations
[get [[spec [[item sized] [item]]] [examples [[[[[a 3] [c 2]] [a] unwrap get] [3] "Get a key from an association"] [[[10 11 12 13] 1 get] [11] "Get an item by index from a list"] [["foobar" 3 get] [\b] "Get a character by index from a string"] [["foobar" encode 3 get] [98] "Get an integer by index from a byte array"] [[[[a 3] [c 2]] [b] unwrap get] [[]] "Get a nonexistent key -> Nothing"]]]]] [assign [[spec [[[item value] [list keys] sized] [association]]] [examples [[[[[a b] [c d]] [a] 5 assign] [[[a 5] [c d]] association] "Assign a new value to an existing key"] [[[[a b] [c d]] [e] 5 assign] [[[a b] [c d] [e 5]] association] "Assign a new value to a new key"] [[[[a b] [c [[d e]]]] [c d] 5 assign] [[[a b] [c []]] [c] [[d 5]] association assign] "Assign a new nested key, promoting to nested association"] [[[[a b] [c [[d e]]]] [1 1 0] 5 assign] [[[a b] [c [5]]]] "Assign a new index in a nested list"] [[[1 2 3] [1 0 0] "foo" assign] [[1 [["foo"]] 3]] "Assign a new index in a nested list"] [[[[a [1 2 3]]] [a 0] 10 assign] [[[a [10 2 3]]] association] "Assign a nested key in a mixed structure of association and list"] [[[1 2 3] [1 2] "foo" assign] [[1 [[] [] "foo"] 3]] "Assign an index creating placeholders for missing list items"]]]]] [unassign [[spec [[[item key] [sized into-association]] [association]]] [examples [[[[[a b] [c d]] [a] unassign] [[[c d]] association] "Unassign a key from an association, promoting from list"] [[[[a b] [c d]] [e] unassign] [[[a b] [c d]] association] "Unassign a key that doesn't exist, only promotes"] [[[[a b] [c d]] [e f] unassign] [[[a b] [c d]] association] "Unassign multiple keys that don't exist only promotes"] [[[[a b] [c [[d e] [f g]]]] [c x] unassign] [[[a b]] [c] [[d e] [f g]] association assign] "Unassign multiple keys where last doesn't exist, only promotes"] [[[[a [[b c] [d e]]]] [a d] unassign] [[] association [a b] [c] unwrap assign] "Unassign associative keylist from nested structure, promoted to association"] [[[0 1 2 [[a b] [c d]]] [3 c] unassign] [[0 1 2] [[a b]] association put] "Unassign mixed keylist from nested structure, inner only is promoted to association"]]]]] [association? [[spec [[item] [boolean]]] [examples [[[[[a b] [c d]] association association?] [yes] "Association is an association"] [[[[a b] [c d]] association?] [[]] "A list is not an association, even if it's possible to promote"] [[1 association?] [[]] "A number is not an association"] [[[] association?] [[]] "An empty list is not an association"] [[[] association association?] [yes] "An empty association is an association"] [[[] [a] 1 assign association?] [yes] "A list promoted to association by assignment, is an association"]]]]] [association [[spec [[item] [association]]] [examples [[[[[a b] [c d]] association [[c d] [a b]] association =] [yes] "A list can be promoted to association"] [[[[a b] [c d]] [[c d] [a b]] association =] [[]] "An association and list are not the same, even if keys/vals are the same"] [[[[a b] [c d]] [[a b] [c d]] association =] [[]] "An association is not the same as the list it was promoted from"]]]]]
;; Associative words [update [[spec [[program [list keys] [sized into-association]] [association]]] [definition [[[lookup] shield] dip ;; m ks v p shielddown assign]] [examples [[[[[a 1] [b 2]] [b] [inc] update] [[[a 1] [b 3]] association] "Update a value in an association"] [[[[a [[c 3] [d 5]]] [b 2]] [a c] [inc] update [a c] lookup] [4] "Update a value in a nested association"] [[[[a [1 3 5 7]] [b 2]] [a 2] [inc] update] [[[a [1 3 6 7]] [b 2]] association] "Update a value in a mixed association/list structure"] [["hi" [[a [[c 3] [d 5]]] [b 2]] [a c] [drop drop 10 15] update [a c] lookup] ["hi" 15] "Update function can't destroy stack items"] [[[[a 1] [b 2]] [d] [5] update] [[[a 1] [b 2] [d 5]] association] "Update creates new key when it doesn't exist"] [[[[a [[c 3] [d 5]]] [b 2]] [a e] [5 6 +] update [a e] lookup] [11] "Update function can ignore previous value"]]]]] [lookup [[spec [[[list keys] sized] [item]]] [definition [[something?] ;; keylist not empty [take swap [get] dip] ;; extract the first key and lookup while drop]] [examples [[[[[a b] [c d]] association [a] lookup] [[b] unwrap] "Lookup the value of a key in an association"] [[[[a b] [c d]] [a] lookup] [[b] unwrap] "Lookup the value of a key, promoting a list to association"] [[[[a b] [c d]] [e] lookup] [[]] "Looking up a key that doesn't exist returns Nothing"] [[[[outer [[a b] [c d]]]] [outer c] lookup] [[d] unwrap] "Lookup in a nested structure, with promotion"]]]]] ;; TODO: fix the case where you just want a value [[type foo]] - only ;; one item but you want the value, not key [type [[spec [[item] [item]]] [definition [[[[empty?] [[nothing] unwrap]] [[word?] [[word] unwrap]] [[number?] [[number] unwrap]] [[string?] [[string] unwrap]] [[bytes?] [[bytes] unwrap]] [[pipe?] [[pipe] unwrap]] [[error?] [[error] unwrap]] [[environment?] [[environment] unwrap]] [[set?] [[set] unwrap]] [[association?] [[[[type] lookup] [[count 1 =] [[first [type] unwrap =] [first second] [first first] if] [[]] if] [[association] unwrap]] [execute] any?]] [[list?] [[list] unwrap]]] decide dropdown]] [examples [[[[[foo 1]] association type] [[foo] unwrap] "An association with one key assumes it is its type"] [[1 type] [[number] unwrap] "Integers are of type number"] [[1.0 type] [[number] unwrap] "Floats are of type number"] [[[] type] [[nothing] unwrap] "Empty list is of type nothing"] [["foo" encode type] [[bytes] unwrap] "A byte array is of type bytes"] [["foo" type] [[string] unwrap] "A string is of type string"] [[[1 2 3] set type] [[set] unwrap] "A set is of type set"] [[[] environment type] [[environment] unwrap] "An environment is of type environment"] [[[[type foo]] association type] [[foo] unwrap] "An association with a single type key, the value is its type"] [[[[type foo] [attr "blah"]] association type] [[foo] unwrap] "An association with a single type key, the value is its type"] [[[[attr1 foo] [attr2 "blah"]] association type] [[association] unwrap] "An association with multiple keys and no type key, is of type association"] [[[[type url] [value "http://foo.com"]] association type] [[url] unwrap] "An association with type/value keys, uses the type key for its type"]]]]] [value [[spec [[[sized into-association]] [item]]] [definition [[count 1 =] ;; if it's a single item [first second] ;; the value is the value of that first item [[value] lookup] ;; otherwise look up the key 'value' if]] [examples [[[[[foo 1]] value] [1] "The value of a single-entry association is the value of the key-value pair"] [[[[type url] [value "http://foo.com"]] value] ["http://foo.com"] "The value of an object is the value key"]]]]] [zip [[spec [[[dispenser values] [dispenser keys]] [list]]] [definition [[] sink ;; save accumulator below args [[something?] both?] ;; stop when either list is empty [[take] both swapdown pair ;; take from each list and pair them up sink [put] dipdown] ;; put them into the accumulator while drop drop]] ;; drop the empty containers [examples [[[[a b c] [1 2 3] zip] [[[a 1] [b 2] [c 3]]] "Zip two lists together into a single list of pairs"] [[[a b c d] [1 2 3] zip] [[[a 1] [b 2] [c 3]]] "Zip two lists of unequal size pads with Nothing values"]]]]] [label [[spec [[[sized labels]] [association]]] [definition [[] swap ;; labels acc [wrap float assign] step]] [examples [[["Alice" 23 "123 Main St" [address age name] label] [[[address "123 Main St"] [age 23] [name "Alice"]] association] "Label values on the stack as an association"]]]]]
Better zip implementation
[a b c d e] [1 2 3] [] sink [swap] [[take] both swapdown pair sink [put] dipdown] while drop drop
[[a 1] [b 2] [c 3] [d []] [e []]]
"asd" [\a \b 1] join
[\a \s \d \a \b 1]
[\b \c] "a" join
"bca"
1.4.2. Sets
;; TODO add 'set' type for spec? [set [[spec [[item] [item]]] [examples [[[[1 2 3 1 2 3] set] [[1 2 3] set] "Promote a list to a set"] [["hello" set] ["helo" set] "Promote a string to a set"]]]]] [set? [[spec [[item] [boolean]]] [examples [[[[1 2 3] set set?] [yes] "A set is a set"] [[[1 2 3] set?] [[]] "A list is not a set"]]]]] [contains? [[spec [[item [item container]] [boolean]]] [examples [[[[1 2 3] 3 contains?] [yes] "List contains a number"] [[[1 2 3 3 5] set 3 contains?] [yes] "A set contains a number"] [[[1 2 3] 4 contains?] [[]] "A list doesn't contain a number"] [[5 3 contains?] [[]] "A number is atomic and doesn't contain anything"] [[[foo] unwrap \o contains?] [[]] "A word is atomic and doesn't contain anything"] [["food" "foo" contains?] [yes] "A string contains a sub-string"] [[[a b c d] [b c] contains?] [[]] "A list doesn't contain a sub-list (due to ambiguity with what 'contains' means with lists)"] [[[a [b c] d] [b c] contains?] [yes] "A list contains another list"] [[[a [b c] d] set [b c] contains?] [yes] "A set contains a list"] [["food" \o contains?] [yes] "A string contains a character"]]]]] [intersection [[spec [[sized sized] [sized]]] [examples [[[[1 2 3] [2 3 4] intersection] [[2 3] set] "Intersection of two lists expressed as set"]]]]]
1.4.3. Generators
;; infinite sequence (generators) functions [[generate [[spec [[program item] [program item]]] [definition [clone [execute] dive]] [examples [[[1 [inc clone] generate] [2 [inc clone] 2] "Generate a value from state"]]]]] [liberate [[spec [[] [program]]] [definition [[take]]]]] [assemble [[spec [[[program generators] dispenser] [sized]]] [definition [[*2 [take] **1 collect] pack shield]] [examples [[[[1 2 3 4 5] [[odd?] keep [inc] each] assemble] [[2 4 6]] "Assemble a sequence from a dispenser and a stack of generators"]]]]] [prime [[spec [[[program body] [program pred] [program init]] [*]]] [definition [[clone [execute] dip] dipdown float join while]] [examples [[[0 [1 2 3 4] [take] [] [swap [+] dip] prime drop drop] [10] "Prime executes init before each time through the loop"]]]]] [into [[spec [[sized program] [list]]] [definition [[generate] dip ;; n swap clone ;; n n r [put ;; r [generate] dip ;; r n swap clone] ;; n n r loop drop]] [examples [[[[[\a \b \c \d] [take] "" into] shield] ["abcd"] "Generate into an empty string"] [[[0 10 1 range [take] 5 dropper [10 *] each [] into] shield] [[50 60 70 80 90]] "Generate a sequence and put it into the given container"]]]]] [collect [[spec [[program] [list]]] [definition [[] into]] [examples [[[[[1 2 3 4] [take] collect] shield] [[1 2 3 4]]] [[[0 10 1 range [take] 5 dropper [10 *] each collect] shield] [[50 60 70 80 90]] "Collect from a generator into an empty list"]]]]] [each [[spec [[program] [program]]] [definition [[generate] swap [bail shielddown] decorate join]] [examples [[[[1 2 3 4] [[clone *] each] assemble] [[1 4 9 16]] "Generate a sequence transforming each value"]]]]] [joiner [[spec [[] [program]]] [definition [[generate [] swap [] [join [generate] dive] while drop]]] [examples [[[[[1 2 3] [4 5 6] [7 8 9]] [joiner] assemble] [[[1 2 3 4 5 6 7 8 9]]]]]]]] [taker [[spec [[] [program]]] [definition [[[positive?] [dec [generate] dive] [[]] if]]] [examples [[[[1 2 3 4 5] [3 taker] assemble] [[1 2 3]]]]]]] [catcher [[spec [[] [program]]] [definition [[[generate] dive [[[clone] dive execute] bail not] [drop []] when]]] [examples [[[[1 2 3 -4 5] [[positive?] catcher] assemble] [[1 2 3]]]]]]] [dropper [[spec [[] [program]]] [definition [[[[positive?] [[generate drop] dip dec] while [generate swap] dip float] bail]]] [examples [[[[1 2 3 4 5] [3 dropper] assemble] [[4 5]]]]]]] [skipper [[spec [[] [program]]] [definition [[] ;; the state (whether threshold reached) [[] ;; condition - whether we've finished dropping or not [[generate] divedown] ;; true - pass everything else through ;; false - generate, check pred, repeat [[[generate] divedown] ;; prime init [[[clone] divedown execute] bail] ;; bring pred up and exec it [drop] ;; if pred passes drop the value prime ;; after this should have value on top [drop true] dip] if]]] [examples [[[[1 2 -3 4 5] [[positive?] skipper] assemble] [[-3 4 5]]]]]]] [keep [[spec [[program] [program]]] [definition [[[[something?] [**1 not]] [execute] every?] pack [clone [[generate] dip ;; pred 1 [drop generate] while] dive]]] [examples [[[[1 2 3 4 5] [[odd?] keep] assemble] [[1 3 5]]]]]]] [group [[spec [[[program group-by]] [association]]] [definition [[*1 shield ;; k v state wrap swap ;; v k state wrap [put] join update] pack [] association ;; state f swap cram]] [examples [[[[[1 2 3 4] liberate [odd?] group] shield] [[[yes [1 3]] [[] [2 4]]] association]]]]]] [split [[spec [[sized] [program sized sized]]] [definition [[empty] [divedown shield] decorated [[[generate] divedown [clone [put] dip] bail] [[[] [drop swap ends? not]] [execute] every?] [drop] prime drop [swap ends?] [[[count] shield] dive [[count] shield] dive swap - [0] dip slice] when [empty] shield swap]]] [examples [[["abcabc" ["b" split] assemble] [["a" "ca" "c"]]] [[[1 2 3 4 2 5] [[2] split] assemble] [[[1] [3 4] [5]]]]]]]] [combinations [[spec [[] [program]]] [definition [[count] shield -1 ;; l idx i [[[swap count =] dive] [drop drop take 0 swap] when [[wrap lookup] dive [pair] bail] shield [inc] dipdown]]] [examples [[[[1 2 3] [combinations] assemble] [[[1 2] [1 3] [2 3]]]]]]]] [frequencies [[spec [[] [association]]] [definition [[] association [wrap [[] [inc] [1] if] update] cram]] [examples [[[["Hello there!" [take] frequencies] shield] [[[\space 1] [\! 1] [\H 1] [\e 3] [\h 1] [\l 2] [\o 1] [\r 1] [\t 1]] association]]]]]] [fold [[spec [[[program reducing-function] [program generator]] [item]]] [definition [[[generate] dive [] [**1 clone] when] pack ;; generate the first item under the loop body [generate clone] dip loop]] [examples [[[[integers 1 dropper 10 taker [+] fold] shield] [55]]]]]] [cram [[spec [[[program reducing-function] [item initial-value] [program generator]] [item]]] [definition [[[generate] dive] [] float prime drop]] [examples [[[[integers 1 dropper 10 taker 0 [+] cram] shield] [55]]]]]] [integers [[spec [[] [program]]] [definition [-1 [inc clone]]]]]] join
;; partition [[] [program]] ;; the spec ;; construct the dynamic definition for partition [[take-chunk [[taker collect dropdown dropdown] ; drop the used-up taker generator join divedeep]] [shift [[[count <=] [swap 0 slice] [[]] if] shield swap]]] [[] [over wrap take-chunk [join shift] bail] [[over] dive wrap take-chunk swap drop shift] if] let ;; add an empty list for the partition state [[]] swap put ;; the definition [[[[1 2 3 4 5 6 7] [2 2 partition] assemble] [[[1 2] [3 4] [5 6] [7]]]]] ;; examples [examples definition spec] label [partition] swap assign [[pairwise [[spec [[program] [*]]] [definition [[[] evert ;; capture stack [2 2 partition] assemble] dip ;; pair up stack items inject ;; run the program on the pairs [joiner] assemble ;; unpair the items unwrap [] swap evert drop]] ;; restore as the stack [examples [[[1 2 3 4 5 [swap] pairwise] [1 4 5 2 3]] [[1 2 3 4 5 [float] pairwise] [2 3 4 5 1]] [[1 2 3 4 5 [[[+] inject] both] pairwise] [1 5 9]]]]]]] join
[[] [program]] ;; the spec ;; construct the dynamic definition for partition [[take-chunk [[taker collect dropdown dropdown] ; drop the used-up taker generator join divedeep]] [shift [[[count <=] [swap 0 slice] [[]] if] shield swap]]] [[] [over wrap take-chunk [join shift] bail] [[over] dive wrap take-chunk swap drop shift] if] [draft dictionary swap [emit encode hashbytes] shield [[[words] swap update] shield dropdown] dip sink [dictmerge] shielddeep] dip float wrap [put] join swapdown [modules] swap update ;; TODO try using confine here [*1 *2 confine] pack join dump
[[[] [program] [[modules [#b64 "yO3LwN0ITlhqAj8T1IKcUqNoiQmEAyrBwbFpGixDtQ8"]] [words 249_entries]] [[] [over wrap take-chunk [join shift] bail] [[over] dive wrap take-chunk swap drop shift] if] confine] 247_entries [words] [[modules []] [words 247_entries]]]
1.5. Dictionary modules
[dictionary [[spec [[] [list]]]]] [cache [[spec [[item bytes] [bytes]]]]] [decache [[spec [[item] [bytes]]]]] [hashbytes [[spec [[bytes] [bytes]]] [examples [[[["foo" encode hashbytes] 2 times =] [yes]] [["foo" encode hashbytes "fop" encode hashbytes =] [[]]]]]]] [resolve [[spec [[word] [word]]]]] [dictmerge [[spec [[[dictionary module] [dictionary original] [bytes hash]] [dictionary]]]]]
[updates [[spec [[[sized word-updates]] [[program single-update]]]] [definition [[[take] [[0] [wrap] update ;; wrap the word name to get a path to update [update] join] each joiner generate] shielddown]]]] [entry [[spec [[[program definition]] [[association full-entry]]]] [definition [[definition] label]]]] [words [[spec [[] [association]]] [definition [dictionary [words] lookup]]]] [module [[spec [[[item wrapped-module-alias-or-hash]] [program]]] [doc "reads a cached module from disk and puts it on the stack as a program"] [definition [decache string read]] [examples [ [["123" encode [crypto] stdmod [hash] confine] [#b64 "_1vRbfFezlcTCUfQCjC1FKukWLoOAeBuvxNXUDbFKSk"]]]]]] [inscribe [[spec [[[bytes raw-module] dictionary] [dictionary]]] [definition [[[hashbytes] ;; calculate module hash [string read execute]] ;; install the module in the dictionary [execute] map ;; fork dropdown unwrap swapdown dictmerge]]]] [draft [[spec [[[sized definitions]] [[program dictionary-updater]]]] [definition [[[1] [entry] update] map ;; create full entries for each definition wrap [join] join]]]] ;; add 'join' to join the entries with the existing dictionary [let [[spec [[program [sized entries]] [*]]] [definition [[draft dictionary swap [emit encode hashbytes] shield [[[words] swap update] shield dropdown] dip sink [dictmerge] shielddeep] dip float wrap [put] join swapdown [modules] swap update [dictionary program] label environment ;; TODO try using confine here [*1 capture evaluate [stack] lookup restore] pack]] [examples [[[[[times5 [5 *]] [doubledec [dec dec]]] [3 times5 doubledec] let execute] [13]] [[[[swap [5]]] ["a" "b" "c" swap] let execute] ["a" "b" "c" 5]] [[[[foo ["outer"]]] ["inner"] let [foo] label [foo] let execute] ["inner"]]]]]] [definition [[spec [[list] [program]]] [definition [[words **1 definition] pack dictionary swap lookup]] [examples [[[1 2 3 [flip] definition execute] [3 2 1] "Fetch the definition of a word and use it"]]]]]
[[plus2 [2 +]]] [5 plus2] [draft dictionary swap [emit encode hashbytes] shield [[[entries] swap update] shield dropdown] dip sink [dictmerge] shielddeep ] dip float wrap [put] join swapdown [modules] swap update [dictionary program] label environment wrap [[snapshot] dive ;; grab a snapshot [stack] swap assign ;; set the env's stack to that value evaluate [stack] lookup restore] ;; promote the result join execute ;[0 dictionary entries] lookup [first [plus2] unwrap =] filter inspect
7
"foo" "bar" [[foop [3 * plus2]] [plus2 [2 +]]] [5 foop] [draft dictionary swap [emit encode hashbytes] shield [shield] dip sink [dictmerge] shielddeep] dip ;; under the let program ;; prog dict hash [wrap] dipdown ;; wrap the hash to make a list of 1 namespace [program dictionary] label environment swap pair ;; creates closure ;; when the closure executes, capture the outer stack first [[[stack] [snapshot] divedown assign] dip using evaluate [stack] lookup restore] join execute ;wrap [[stack] [snapshot] divedown assign evaluate [stack] lookup restore] join ; execute
[a b c d e] [take] 2 2 [] [[take-chunk [[taker collect dropdown dropdown] ; drop the used-up taker generator join divedeep]] [shift [[[count <=] [swap 0 slice] [[]] if] shield swap]]] [[] [over wrap take-chunk [join shift] bail] [[over] dive wrap take-chunk swap drop shift] if] let ;; add an empty list for the partition state ;[[]] swap put collect
[[a b] [c d] [e]] [[[dictionary dictionary_redacted] [program [[] [over wrap take-chunk [join shift] bail] [[over] dive wrap take-chunk swap drop shift] if]] [resolver [#b64 "yO3LwN0ITlhqAj8T1IKcUqNoiQmEAyrBwbFpGixDtQ8="]]] [stack] [snapshot] divedown assign environment evaluate [stack] lookup restore] [] 2 2 [take] []
[a b c d e] 2
[a b]
[[take-chunk [[taker collect dropdown dropdown] ; drop the used-up taker generator join divedeep]] [shift [[[count <=] [swap 0 slice] [[]] if] shield swap]]] [[] [over wrap take-chunk [join shift] bail] [[over] dive wrap take-chunk swap drop shift] if] let partition dropdown [first [dictionary] lookup [first] map set] both
[* + - / < <= = > >= abs addmethod and animate any? assert assign association association? attend autoformat bail bits both both? branch butlast bytes? cache ceiling clone clonedeep clonedown close compare confine contains? count cut database days dec decache decide decodejson decorate decorated definition dictionary dictmerge dip dipdeep dipdown dive divedeep divedown draft drop dropdeep dropdown emit empty empty? encode encodejson encodenumber encodestring ends? entry environment error? eval-step evaluate even? evert every? execute exp fail file-in file-out filter finished? first flatten flip float floor format future generator get handle handoff hashbytes hours if inc indexed indexer indexof inject inscribe inspect interpose intersection join label last let list? log lookup loop map max method? milliseconds min minutes mod module negative? not number number? odd? or over pad pair pair? persist pipe-in pipe-out pipe? pop positive? prepend prime primrec print put quot radix range read receiver recover recur rem repeat rest restore retry reverse round second seconds select sender serversocket set set? shield shielddeep shielddown shift sink siphon sleep slice slurp snapshot socket something? sort sort-indexed spawn spit sqrt stage standard starts? step string string? swap swapdown take take-chunk template timer times timestamps toe tos triplet tunnel type unassign under until unwrap update updates using value walk when while within? word word? wrap xor yes zero? zip] [* + - / < <= = > >= abs addmethod advance and animate any? assemble assert assign association association? attend autoformat bail bits both both? branch break breakpoint butlast bytes? cache catcher ceiling clone clonedeep clonedown close collect combinations compare confine contains? count cram cut database days dec decache decide decodejson decorate decorated definition dictionary dictmerge dip dipdeep dipdown dive divedeep divedown draft drop dropdeep dropdown dropper dump each emit empty empty? encode encodejson encodenumber encodestring ends? entry environment error? eval-step evaluate even? evert every? execute exp fail file-in file-out filter finished? first flatten flip float floor fold format frequencies future generate generator get group handle handoff hashbytes heatmap hours if inc indexed indexer indexof inject inscribe inspect integers interpose intersection into join joiner keep label last let liberate list? log lookup loop map max method? milliseconds min minutes mod module negative? not number number? odd? or over pad pair pair? pairwise partition persist pipe-in pipe-out pipe? pop positive? prepend prime primrec print put quot radix range read receiver recover recur rem repeat rest restore retry reverse round second seconds select sender serversocket set set? shield shielddeep shielddown shift sink siphon skipper sleep slice slurp snapshot socket something? sort sort-indexed spawn spit split sprint sqrt stage standard starts? step stepper string string? swap swapdown take take-chunk taker template timer times timestamps toe tos tracer triplet tunnel type unassign under until unwrap update updates using value walk when while within? word word? wrap xor yes zero? zip]
1.6. Math
[+ [[spec [[number number] [number]]] [examples [[[1 2 +] [3]] [[1.1 2.2 + 3.3 0.001 within?] [yes]] [[1 2.2 +] [3.2]]]]]] [- [[spec [[number number] [number]]] [examples [[[2 1 -] [1]] [[1.1 2.2 - -1.1 0.00001 within?] [yes]] [[2.2 1 - 1.2 0.00001 within?] [yes]]]]]] [* [[spec [[number number] [number]]] [examples [[[4 3 *] [12]] [[10 1.5 * 15 0.0001 within?] [yes]] [[5 0 *] [0]] [[5 -1 *] [-5]]]]]] [/ [[spec [[number number] [number]]] [examples [[[12 3 /] [4]] [[15 1.5 /] [10.0]] [[0 1 /] [0]] [[1 0 / handle [reason] lookup] [1 0 "division by zero"]]]]]] [quot [[spec [[number number] [number]]] [examples [[[16 5 quot] [3]]]]]] [rem [[spec [[number number] [number]]] [examples [[[17 5 rem] [2]]]]]] [mod [[spec [[number number] [number]]] [examples [[[17 5 mod] [2]]]]]] [exp [[spec [[number number] [number]]] [examples [[[2 5 exp] [32]]]]]] [log [[spec [[number number] [number]]] [examples [[[32 2 log] [5]]]]]] [floor [[spec [[number] [number]]] [examples [[[2.1 floor] [2]]]]]] [ceiling [[spec [[number] [number]]] [examples [[[2.1 ceiling] [3]]]]]] [round [[spec [[number] [number]]] [examples [[[2.1 round] [2]]]]]] [sqrt [[spec [[number] [number]]] [examples [[[9 sqrt] [3]] [[81 sqrt] [9]]]]]] [inc [[spec [[number] [number]]] [examples [[[1 inc] [2]] [[-1 inc] [0]] [[99 inc] [100]]]]]] [dec [[spec [[number] [number]]] [examples [[[2 dec] [1]] [[0 dec] [-1]] [[100 dec] [99]]]]]] [abs [[spec [[number] [integer]]] [examples [[[2.1 abs] [2.1]] [[-0.2 abs] [0.2]] [[-2 abs] [2]] [[0 abs] [0]]]]]] [odd? [[spec [[number] [boolean]]] [examples [[[1 odd?] [yes]] [[-1 odd?] [yes]] [[4 odd?] [[]]]]]]] [even? [[spec [[number] [boolean]]] [examples [[[2 even?] [yes]] [[-2 even?] [yes]] [[3 even?] [[]]]]]]] [zero? [[spec [[number] [boolean]]] [examples [[[0 zero?] [yes]] [[0.0 zero?] [yes]] [[-0.00001 zero?] [[]]] [[1.1 zero?] [[]]]]]]] [number? [[spec [[item] [boolean]]] [examples [[[[1] number?] [[]]] [[[] number?] [[]]] [[5 number?] [yes]] [[5.01 number?] [yes]]]]]] [number [[spec [[item] [number]]] [examples [[["12" number] [12]] [["-11.1" number] [-11.1]] [["a" first number] [97]]]]]]
[positive? [[spec [[number] [boolean]]] [definition [0 >]]]] [negative? [[spec [[number] [boolean]]] [definition [0 <]]]] [within? [[spec [[number number] [boolean]]] [definition [[- abs] dip <]] [examples [[[1.0 2.0 + 3 0.001 within?] [yes]]]]]]
1.7. Serialization
[read [[spec [[string] [item]]] [examples [[["[1 [2] 3]" read] [[1 [2] 3]]]]]]] [emit [[spec [[item] [string]]] [examples [[[[1 [2] 3] emit] ["1 [2] 3"]]]]]] [autoformat [[spec [[string] [string]]] [examples [[["[[foo bar] [baz [[quux floop] [toop zoop]]]]" autoformat] ["[[foo bar]\n [baz [[quux floop]\n [toop zoop]]]]"]]]]]]
1.8. Boolean logic
[yes [[spec [[] [word]]]]] ;; self-inserts [and [[spec [[item item] [item]]] [examples [[[1 odd? 2 even? and] [yes]] [[2 3 and] [3]] [[[] 3 and] [[]]] [["" 3 and] [[]]]]]]] [or [[spec [[item item] [item]]] [examples [[[1 odd? 3 even? or] [yes]] [[1 2 or] [1]] [[[] 2 or] [2]] [[[] [] or] [[]]]]]]] [not [[spec [[item] [boolean]]] [examples [[[1 even? not] [yes]] [[[] not] [yes]] [[yes not] [[]]] [[[] not] [yes]]]]]]
1.9. Byte encoding and decoding
[encodestring [[spec [[string] [bytes]]] [examples [ [["foo" encodestring] [#b64 "Zm9v"]] [["" encodestring] [#b64 ""]]]]]] [encodenumber [[spec [[number] [bytes]]] [examples [[[12 encodenumber] [#b64 "AAAAAAAAAAw"]] [[12.3 encodenumber] [#b64 "QCiZmZmZmZo"]]]]]] [decodejson [[spec [[string] [item]]] [examples [[["12" decodejson] [12]] [["12.01" decodejson] [12.01]] [["\"foo\"" decodejson] ["foo"]] [["{\"foo\": 12, \"bar\": \"baz\"}" decodejson] [[["foo" 12] ["bar" "baz"]] association]] [["[1,\"foo\"]" decodejson] [[1 "foo"]]]]]]] [encodejson [[spec [[item] [string]]] [examples [[[12 encodejson] ["12"]] [[12.01 encodejson] ["12.01"]] [["foo" encodejson] ["\"foo\""]] [[[["foo" 12] ["bar" "baz"]] association encodejson decodejson] [[["foo" 12] ["bar" "baz"]] association]] [[[1 "foo"] encodejson] ["[1,\"foo\"]"]]]]]] [bytes? [[spec [[item] [boolean]]] [examples [[["foo" bytes?] [[]]] [[#b64 "Zm9v" bytes?] [yes]] [[[#b64 "Zm9v"] bytes?] [[]]] [["foo" encode bytes?] [yes]]]]]] [xor [[spec [[item] [item]]] [examples [[[10 12 xor] [6]] ;; 10 = 01010, 12 = 01100, 00110, 6 [["foo" encode "bar" encode xor] [#b64 "BA4d"]]]]]] [bits [[spec [[item] [sized]]] [definition [encode [[2 radix 8 0 pad] each joiner] assemble unwrap]] [examples [[["foo" bits] [[0 1 1 0 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 0 1 1 1 1]]]]]]]
[[encode [[spec [[item] [bytes]]] [definition [[[[bytes?] []] [[string?] [encodestring]] [[number?] [encodenumber]] [[true] [emit encode]]] decide]] [examples [[[12 encode] [#b64 "AAAAAAAAAAw"]] [["foo" encode] [#b64 "Zm9v"]] [["foo" encode encode] [#b64 "Zm9v"]] [["" encode] [#b64 ""]]]]]] [radix [[spec [[integer integer] [list]]] [definition [[[/] shield swap [*] shielddown swapdown - swap [prepend] dip] swap prepend [[] swap [positive?]] dip while drop]] [examples [[[7 2 radix] [[1 1 1]]] [[9 3 radix] [[1 0 0]]] [[255 16 radix] [[15 15]]]]]]]] join
1.10. Strings
[string [[spec [[item] [string]]] [examples [[[1 string] ["1"]] [[[1 2 3] string] ["[1 2 3]"]] [[[] string] [""]]]]]] [format [[spec [[list string] [string]]] [examples [[["foo {} bar {} baz" ["abc" "def"] format] ["foo abc bar def baz"]]]]]] [string? [[spec [[item] [boolean]]] [examples [[["hi" string?] [yes]] [["" string?] [yes]] [[["hi"] string?] [[]]] [[yes string?] [[]]]]]]] ;; Don't really belong here but good enough for now [word? [[spec [[item] [boolean]]] [examples [[[[foo] unwrap word?] [yes]] [[yes word?] [yes]] [[1 word?] [[]]] [["yes" word?] [[]]]]]]] [word [[spec [[item] [word]]] [examples [[["foo" word] [[foo] unwrap]]]]]] [inspect [[spec [[item] [string]]]]]
1.11. Error handling
[error? [[spec [[item] [boolean]]]]] ;; handle is a special word only used to unwind the program on ;; error, if there's no error and we end up reaching this word, we ;; ignore it. [handle [[spec [[] []]] [definition []]]] [fail [[spec [[sized] [*]]]]]
[[assert [[spec [[program] [*]]] [definition [snapshot ;; save stack to print in err message [shield] dive ;; run the assertion under the saved stack [drop] ;; if passes, drop the saved stack, dont need [string ["assertion failed "] dip join fail] ;; else throw err branch]]]] [recover [[spec [[program program] [*]]] [definition [[[handle] join] dip ;; add handle to the end of test [snapshot] dipdown ;; rec test ss sink inject ;; res rec [first error?] ;; err? res rec [first swap execute];; drop the snapshot and run recovery [evert drop] ;; use snapshot as stack if]] [examples [[[[+] [drop 1 [+] [drop 2 +] recover] recover] [3]] [[[1 2 "oh fudge"] [[5 +] [drop 5] recover] map] [[6 7 5]]] [[[swap] [drop swap] recover] [swap]]]]]] [retry [[spec [[error] [*]]] [definition [[unwound] lookup execute]] [examples [[[2 3 "four" * + handle [drop 4] dip retry] [14]]]]]]] join
1.12. Methods
We want a way of adding methods to a word that's already set up as a
simple 'decide' form. This will add the method at the beginning -
adding it at the end is not good because often there's a catchall
condition at the end, and adding beyond that means the new condition
is unreachable. Adding at the beginning is not always what the user
wants either, though. So maybe this could be improved by taking
another argument: a program to combine the item and the existing list
(that defaults to prepend
here).
[[addmethod [[spec [[[program method] [program condition] [program definition]] [[program newdefinition]]]] [definition [[[*2 *1] prepend] pack [0] swap update]] [examples [[[[[[[count 3 >] ["foo" put]] [[not] ["bar" put]]] decide] [count 1 =] [rest] addmethod] [[[[[count 1 =] [rest]] [[count 3 >] ["foo" put]] [[not] ["bar" put]]] decide]]]]]]] [method? [[spec [[program] [boolean]]] [definition [[[first [[pair?] [[list?] every?]] every?] [second [decide] unwrap =]] every?]]]]] join
1.13. Database
[[[list selection] [list constraints]] [string]] [[fork [[execute] map]] [triangle [[[] [[take] dip swap [[put] shield sink swap pair] bail] collect] shielddown]] [indexed-as-property [swap indexed [unwrap sink assign] map dropdown]] [join-all [[first empty] shield swap [join] step]] [selectkeys [set [*1 [first] dive contains?] pack filter]] [invert [[reverse] map association]] ;; datalog variables [variable? [[[word?] [string last \? =]] [execute] every?]] [variable= [[[pair [variable?] every?] [=]] [execute] every?]] ;; datalog constraints [slots [[entity attribute value]]] [slot-combos [slots [slots [pair] map] map join-all]] [constraint [unwrap slots reverse label]] ;; links between datalog constraints [links [slot-combos [[wrap] map unwrap swapdown [[[lookup] inject] both] pairwise variable=] filter [unwrap pair sink pair [[index] lookup] map swap zip] map]] [all-links [[] sink [[[[index] lookup] shield] both ;; lookup the indices of both constraints [swapdown] dip sink ;; move the indices under the constraints [links] shielddown swap [dropdown dropdown join] dip] step drop]] [format-link [[join] inject unwrap [string] map "c{0}.{1} = c{2}.{3}" swap format]] ;; formatting pieces of query data into text [anded-together [" AND " interpose join-all]] ;; where clause data processing [where-data [[[index] lookup] shield swap [[[second variable? not] [first [index] unwrap = not]] [execute] every?] filter [swap prepend] map dropdown]] [format-where [[string] map "c{0}.{1} = :c{0}{1}" swap format]] [make-where [first [where] lookup anded-together]] [format-join [[[[on] lookup] [[where] lookup] [[index] lookup string]] [execute] map [join anded-together] inject "JOIN EAV c{1} ON {0}" swap format]] [make-query [rest [[on] [[format-link] map] update [format-join] shield [join] swap assign] map]] ;; SQL parameters for rusqlite [param-name [[string] map ":c{0}{1}" swap format]] [extract-params [[] association swap [[params] lookup join] step]] ;; SELECT clause [wordval? [second word?]] [invert [[reverse] map association]] [validate [[[second not] [first "All selected query variables must appear somewhere in constraints" [reason variable] label fail] when] map]] [select-data [swap [[slots selectkeys invert] shield [wordval?] filter join association] map swap [[[[index *1] selectkeys] pack ;; make the program to cut down map [count 2 =] filter first [second] map [first number?] [reverse] when] ;; items are in random order due to coming from association, fix the order map] shield dropdeep zip validate]] ;; query [extract-data [[[[unwrap all-links] [first where-data ; [join] inject unwrap ;; build the query param map [[[] swap [[param-name] shield [last] dip wrap swap assign] step] ;; build the actual query where clauses [[format-where] map]] fork]] fork] shield ;; combine extracted items [first] dip ;; keep the original constraint to add properties to unwrap unwrap [where params on] label join]] [format-select [[unwrap swap string butlast ;; remove the ? from the variable name for result column put [string] map "c{1}.{0} as {2}" swap format] map ", " interpose join-all]]] ;; This is the program we need to modify that is `query` [swap ;; expand all combinations of constraints [constraint] map ;;[] prepend ;; an empty constraint to represent the orignal EAV table we're joining with [index] indexed-as-property triangle ;; for each pair of constraints, build the "ON" clause data for the JOIN [extract-data] map [[extract-params] [make-query] [make-where] [swap select-data]] fork dropdown ;; don't need original anymore unwrap float [[join] lookup] map swap format-select [" " interpose join-all] dip triplet reverse "SELECT {0} from EAV as c0 {1} WHERE {2}" swap format swap dropdeep] let [definition spec] label [query] swap assign
1.14. Pipes
[pipe? [[spec [[item] [boolean]]] [examples [[[timestamps pipe?] [yes]] [[standard pipe?] [yes]] [[[1 2 3] pipe?] [[]]] [[5 pipe?] [[]]]]]]] [animate [[spec [[environment] []]]]] [attend [[spec [[list] [list]]]]] [file-in [[spec [[string] [pipe]]]]] [file-out [[spec [[string] [pipe]]]]] [handoff [[spec [[] [pipe]]]]] [receiver [[spec [[pipe] [pipe]]]]] [select [[spec [[[list pipes]] [item pipe [list pipes]]]]]] [sender [[spec [[pipe] [pipe]]]]] [serversocket [[spec [[integer string] [pipe]]]]] [socket [[spec [[integer string] [pipe]]]]] [standard [[spec [[] [pipe]]]]] [timer [[spec [[integer] [pipe]]]]] [timestamps [[spec [[] [pipe]]]]] [database [[spec [[[sized params] string] []]]]] [persist [[spec [[sized] []]]]]
[[pipe-in [[spec [[item] [pipe]]] [definition [association [[[type [file] unwrap =] [value file-in]] [[type [stdout] unwrap =] [stdout]]] decide]]]] [tunnel [[spec [[item] [pipe]]] [definition [association [[[type [ip-host] unwrap =] [clone [port] lookup [[address] lookup] dip serversocket]] [[type [ip-client] unwrap =] [clone [port] lookup [[address] lookup] dip socket]]] decide]]]] [pipe-out [[spec [[item] [pipe]]] [definition [association [[[type [file] unwrap =] [value file-out]] [[type [ip-host] unwrap =] [clone [port] lookup [[address] lookup] dip serversocket]]] decide]]]] [spit [[spec [[item [item target]] []]] [definition [[pipe-in] dip encode put drop]]]] [slurp [[spec [[pipe] [item]]] [definition [[take] [join] fold string [drop drop] dip]]]] [print [[spec [[string] []]] [definition [[standard] dip "\n" join encode put drop]]]] ;;[slurp [[spec [[[item target]] [item pipe]]]]] [sleep [[spec [[integer] []]] [definition [timer take drop drop]]]] [future [[spec [[program] [pipe]]] [definition [handoff swap [[**1 snapshot] ;; return entire stack dive put drop] pack dictionary swap spawn animate]] [examples [[[1 [2 +] future take dropdown] [1 [3]]]]]]] [generator [[spec [[[program generator-maker]] [[program wrapped-generator]]]] [definition [[] swap inject [[generate] inject take]]]]] ;; generate from the wrapped generator [siphon [[spec [[[receptacle output] [program generator]] [[receptacle output]]]] [description "Generates values from a wrapped generator (stacked generator inside a list), until exhausted, puts all items into the output receptacle"] [definition [[] ;; placeholder that gets dropped (next ;; iteration it will hold a copy of the last ;; element which is only needed to check if ;; the loop continues and can be dropped ;; after) [empty?] ;; stop when generator returns ;; nothing [drop ;; the last value [generate clone] dip sink [[put] bail] dip] until drop drop sink drop drop]] ;; the now-empty dispenser [examples [[[[[integers 5 taker] generator [] siphon] shield] [[0 1 2 3 4]]]]]]] [close [[spec [[pipe] []]] [definition [drop]]]]] join
1.15. Crypto
[random [[spec [[integer] [bytes]]]]] [key [[spec [[bytes] [bytes]]] [examples [[[["foo" encode key] 2 times =] [yes]]]]]] [sign [[spec [[[bytes message] [association key]] [bytes]]]]] [verify [[spec [[[bytes signature] [bytes message] [sized key]] [boolean]]] [examples [[["foo" encode key "we attack at dawn" encode [sign] shield verify] [yes]]]]]]
[[delegated [[spec [[[association pubkey]] [program]]] [definition [[[sink ;; css cs pk [[hash] [shield dip] decorated ;; css csh cs pk float ;; cs css csh pk [verify] dip [[]] ;; the program to run if the child script isn't authorized branch] ;; runs the child script if the sig on its hash is verified [drop drop ;; the sig and (empty) child script -> pk sig msg sink ;; sig msg pk verify] [clone] dipdown branch] [[]] recover] swap prepend]]]] ;; prepend the pubkey [hash [[spec [[item] [bytes]]] [definition [[[[bytes?] [hashbytes]] [[true] [encode hash]]] decide]]]]] join
1.16. Time and date
[[milliseconds [[spec [[integer] [integer]]] [definition []]]] [seconds [[spec [[integer] [integer]]] [definition [1000 *]]]] [minutes [[spec [[integer] [integer]]] [definition [seconds 60 *]]]] [hours [[spec [[integer] [integer]]] [definition [minutes 60 *]]]] [days [[spec [[integer] [integer]]] [definition [hours 24 *]]]]] join
1.17. Nested Environments
[environment [[spec [[sized] [environment]]] [examples [[[[[program [1 2 3]]] environment eval-step [stack] lookup] [[1]]]]]]] [environment? [[spec [[item] [boolean]]] [examples [[[[[program [1 inc]]] environment environment?] [yes]] [[[[program [1 inc]]] environment?] [[]]]]]]] [eval-step [[spec [[environment] [environment]]] [examples [[[[[program [1 inc]]] environment eval-step eval-step [stack] lookup] [[2]]]]]]] [evaluate [[spec [[item] [environment]]] [examples [[[[[program [1 2 3 4 + *]]] environment evaluate [stack] lookup] [[14 1]]]]]]] [finished? [[spec [[environment] [boolean]]] [examples [[[[[program [1 2 3 4 + *]]] environment finished?] [[]]] [[[[program [1 2 3 4 + *]]] environment evaluate finished?] [yes]]]]]] [using [[spec [[[list modules] [sized env]] [environment]]]]] [use [[spec [[[program [list modules]] [*]]]] [definition [[program] label environment swap ;; lm env [[stack] [snapshot] divedown assign] dip ;; capture the stack at runtime using ;; set up the resolver evaluate ;; execute the program in the inner environment [stack] lookup restore ;; replace the stack with the result from the inner env ]]]]
[tos [[spec [[environment] [item]]] [definition [[stack] lookup first]] [examples [[[[[stack [1 2 3]] [program [[+] step]]] tos] [1]]]]]] [top [[spec [[environment] [item]]] [definition [[program] lookup first]] [examples [[[[[stack [1 2 3]] [program [[+] step]]] toe] [[+]]]]]]] [stage [[spec [[program] [environment]]] [definition [[program] label environment]]]] [capture [[spec [[environment] [environment]]] [doc "Capture the outer stack and assign it to the inner env's stack"] [definition [[stack] [snapshot] divedown assign]]]] [spawn [[spec [[program dictionary] [environment]]] [definition [[snapshot] dipdown ;; p d s [program dictionary stack] label environment]] [examples [[[1 2 3 dictionary [swap clone] spawn] [1 2 3 [[program [swap clone]] [stack [3 2 1]]] environment]]]]]] [confine [[spec [[[program module] dictionary] [*]]] [definition [spawn evaluate [stack] lookup restore]]]]
1.17.1. Debugging
[[break [[spec [[[program condition] environment] [[program condition] environment]]] [definition [[[[swap something?] ;; still running [execute not]] ;; check condition not true yet [execute] every?] ;; break? [[eval-step] dip] ;; evaluate the environment one step while]]]] [breakpoint [[spec [[] []]] [definition []]]] [sprint [[spec [[environment] [environment]]] [definition [[[program 0] lookup wrap [breakpoint] =] break drop ;; the condition [] [eval-step] when]]]] ;; advance past the breakpoint word if the program isn't complete [advance [[spec [[environment] [environment]]] [definition [[[program] lookup count] shield swap ;; count up the program length, we'll run until it's smaller than this [[program] lookup count ;; only stop if expr empty or shorter than we started off [[positive?] [<=]] [execute] every?] [eval-step] ;; evaluate the environment one step while dropdown]]]] ;; drop the program length item [stepper [[spec [[] [program]]] [definition [[eval-step clone]]]]] [tracer [[spec [[program] [[program generator]]]] [definition [stage stepper]]]] [dump [[spec [[] []]] [definition [snapshot wrap emit autoformat print]]]] [heatmap [[spec [[program] [association]]] [definition [[tracer ;; what item is being executed [[program] lookup [first] ;; don't emit [] or the execution stops, use 0 instead bail 0 or] each [word?] keep ;; count only words, which filters out the 0's from above frequencies] shielddown]]]]] join
[[evaluating? [[program] lookup [evaluate] starts?]] [with-innermost [[[] swap [[evaluating?] [[stack 0] clone [lookup] dip swap [join] dip ] ;; append the next part of the path to the accumulator while swap] shield dropdeep] dip ;; under the stepping prog [update] shielddown flip drop ;; find which envs are finished and remove ;; 'evaluate' from parent [0 -2 slice clone] [collect] shielddeep [[[[[evaluating?] [[stack 0] lookup finished?]] [execute] every?] [[program] [rest] update] when] [update] shielddown flip drop drop] step]]] join
1.17.1.1. Examples
- Count the number of times each word is executed while running a program.
[[program [10 [0 >] [clone dec] while]]] ;; the sample program to run environment evaluate
[[stack [0 1 2 3 4 5 6 7 8 9 10]] [program []]]
10 [0 >] [clone dec] while
[0 1 2 3 4 5 6 7 8 9 10]
[swap] unwrap word?
[yes]
"Increment the counter, or set to 1 if nothing"
[] [inc] bail 1 or
1
[] ;; empty list to put word counts in [[program [3 [0 >] [clone dec] while]]] ;; the sample program to run environment [[program] lookup something?] ;; something still in the program, keep running [[[program] lookup first] shield ;; get the item we're about to execute swap ;; put it under the environment [[word?] ; if it's a word [wrap [[inc] bail 1 or] update] ;; the results, the count for the word about to execute [drop] ;; if it's not a word, do nothing if] dip eval-step] ;; evaluate the environment one step while drop ;; drop the environment and just report the word counts
[[wrap 1] [step 2] [first 4] [snapshot 4] [execute 1] [put 1] [inject 4] [loop 4] [dec 3] [decorate 1] [swap 5] [unwrap 14] [take 4] [join 1] [> 4] [while 1] [shield 4] [dipdown 1] [evert 16] [clone 8] [dip 9]]
Now that we have generators and
frequencies
I think this can be greatly simplified:[5000 [0 >] [clone dec] while] ;; the sample program to run tracer [[program 0] lookup "foo" or] each [word?] keep frequencies
[[> 1001] [clone 2002] [dec 1000] [decorate 2] [decorated 1] [dip 2007] [dip 2] [dipdown 1] [evert 4004] [execute 1] [first 1001] [inject 1001] [join 1] [loop 1001] [put 3] [shield 1001] [shield 1] [snapshot 1001] [step 5] [swap 1002] [take 1001] [unwrap 1001] [while 1] [wrap 3]] [clone [[generate] dip [drop generate] while] dive] [[[something?] [word? not]] [execute] every?] [generate [[[program 0] lookup "foo" or] bail] shielddown] [eval-step clone] []
- CANCELED spec checking
clojure spec check can be replaced with predicate programs, that will be run with
shield
before the actual word and if it returns false, will raise an error. - TODO Trace output
[] ;; results [[program [1 [2 3 4 5] [*] step]]] ;; the sample program to run environment [[program] lookup something?] ;; break? [eval-step clone [put] dip] ;; evaluate the environment one step while
[[[stack [120]] [program []]] [[[stack [1]] [program [[2 3 4 5] [*] step]]] [[stack [[2 3 4 5] 1]] [program [[*] step]]] [[stack [[*] [2 3 4 5] 1]] [program [step]]] [[stack [[*] 2 1]] [program [execute [3 4 5] [*] step]]] [[stack [2 1]] [program [* [3 4 5] [*] step]]] [[stack [2]] [program [[3 4 5] [*] step]]] [[stack [[3 4 5] 2]] [program [[*] step]]] [[stack [[*] [3 4 5] 2]] [program [step]]] [[stack [[*] 3 2]] [program [execute [4 5] [*] step]]] [[stack [3 2]] [program [* [4 5] [*] step]]] [[stack [6]] [program [[4 5] [*] step]]] [[stack [[4 5] 6]] [program [[*] step]]] [[stack [[*] [4 5] 6]] [program [step]]] [[stack [[*] 4 6]] [program [execute [5] [*] step]]] [[stack [4 6]] [program [* [5] [*] step]]] [[stack [24]] [program [[5] [*] step]]] [[stack [[5] 24]] [program [[*] step]]] [[stack [[*] [5] 24]] [program [step]]] [[stack [[*] 5 24]] [program [execute]]] [[stack [5 24]] [program [*]]] [[stack [120]] [program []]]]]
- DONE Step count limiting
When testing or debugging, limit the number of steps to avoid a possible infinite loop.
200 ;; step count remaining [[program [10 [0 >] [clone dec] while]]] ;; the sample program to run environment [[program] lookup something? ;; something still in the program [positive?] dip and] ;; still step budget remaining [eval-step ;; evaluate the environment one step [dec] dip] ;; decrease the step budget while ;[stack] lookup ;; return the output
[[program [take dip evert first [clone dec [0 >] shield] loop]] [stack [[[0 >] 4 5 6 7 8 9 10] 4 5 6 7 8 9 10]]] 0
- DONE Breakpoint
[[[[toe [+] unwrap =] [tos 3 >]] [execute] every?] ;; when to stop - when we're about to add and tos already >3 [0 [1 2 3 4 5] [+] step] ;; the sample program to run environment [[[[program] lookup something?] ;; something still in the program [swap execute not]] ;; don't stop yet [execute] every?] ;; break? [eval-step] ;; evaluate the environment one step while]
- TODO Step over
[[0 [1 2 3 4 5] [+] step] ;; the sample program to run environment [[program] lookup count] shield swap;; count up the program length, we'll run until it's smaller than this [[program] lookup count [[positive?] [<=]] [execute] every?] ;; only stop if expr empty or shorter than we started off [eval-step] ;; evaluate the environment one step while]
1.18. TODO Functional environment
There are use cases for kcats where you don't want a program to be able to mess with external resources like files, network sockets etc nor be able to spawn new threads, the program it's running should be a pure function and this module lets you enforce that.
[pipe-in pipe-out channel timeout handoff file-in file-out timestamps standard serversocket animate future spit tunnel database] [wrap unassign] step
2. Issues
2.1. DONE Get rid of platform-specific definitions
2.2. DONE fix evaluate
[[program [1 1 +]]] environment evaluate [stack] lookup
[[2]]
2.3. TODO merkle tree functions
"foo" "bar" join hash "foobar" hash =
yes
First let's figure out how to represent a tree:
;[5 [[3 [[1c []] ; [2c []]]] ; [4 [[3c []]]]]] [[hash []] [children [second]] [data [first]] [node [[] pair]] [empty-node [#b64 "" hash node]] [child [[children] dip get]] [addchild [[pop] dip put put]] [rawpath [1 [interpose] shield swap prepend dropdown]] [siblings [[] node sink [addchild] dip addchild]] ;[path [[] [take swap [child] dip path] [drop] if]] [path [dec 2 radix rawpath]] [parent [butlast butlast]] [rehash [[children [data] map] shield [first] shield empty swap [join] step hash wrap [0] swap update]] ;; lopsidedtree n [balance []] ;; node tree cur-ct [add [[clone path [pop zero?] [parent] when] dipdown ;; node tree path ct swapdown ;; node path tree ct []]] [add [[odd?] ;; insert an unbalanced node (empty sibling) [empty-node siblings [path parent]] ;; otherwise replace the empty sibling [] ]]] ; ["" drop ; ;[0 []] 1 node addchild 2 node 3 node addchild addchild ; ;[1 0] 1 [interpose] shield swap put dropdown lookup ; "foo" hash node "bar" hash node siblings ; ;; update the root node ; rehash ; ; now add a new sibling ; "baz" hash node siblings ; rehash ; 3 path [pop zero?] [butlast butlast] [] if ; ;dump ; ["quux" hash node siblings rehash ] update ; ] [["foo" "bar" "baz" "quux"] [node] map [] let
[["foo" []] ["bar" []] ["baz" []] ["quux" []]]
1234
- 12
- 1
- 2
- 34
- 3
- 4
- 5
- 6
- 12
["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] ["bazquux" [["baz" []] ["quux" []]]]]] ["" []]
interpose impl
[1 3 4] [foo] unwrap interpose
[1 foo 3 foo 4]
[0 [[1 []] [2 [[3 []]]]]] [1 0] 1 [interpose] shield swap prepend 0 put dropdown [inc] update
[0 [[1 []] [2 [[4 []]]]]]
We need a function that, given a number n, gives the path in the
merkle tree. eg, 8 would be 1 1 1. Is it just n-1
in binary?
6 would be 1 0 1. Ok so just write a function to expand binary digits:
8 dec 2 radix
[1 1 1]
["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] ["baz" []]]] [1 1] [drop drop "hi" "there"] update
["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] "there"]]
[[hash []] [children [second]] [data [first]] [node [[] pair]] [child [[children] dip get]] [addchild [[pop] dip put put]] [siblings [[] node sink [addchild] dip addchild]] ;[path [[] [take swap [child] dip path] [drop] if]] [path [dec 2 radix nodepath]] [rehash [[children [data] map] shield [first] shield empty swap [join] step hash wrap [0] swap update]]] [["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] ["baz" []]]] [1 1] ["bazquux" [["baz" []] ["quux" []]]] assign] let
["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] ["bazquux" [["baz" []] ["quux" []]]]]]
[["bazquux" [["baz" []] ["quux" []]]] [1 1] ["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] ["baz" []]]]] reverse unwrap assign
["foobarbaz" [["foobar" [["foo" []] ["bar" []]]] ["bazquux" [["baz" []] ["quux" []]]]]]
[ [children [second]] [data [first]] [node [[] pair]] [addchild [[pop] dip put put]] [siblings [[] node sink [addchild] dip addchild]] [nodepath [1 [interpose] shield swap prepend dropdown]] [padded [[[[count] shield] dive -] dip swap repeat swap join]] [path [[dec 2 radix] dip 2 log ceiling 0 padded nodepath]] ;; item-ct index [depth []] [rehash [[children [data] map] shield [first] shield empty swap [join] step hash wrap [0] swap update]] [joiner [[2 2 partition [[count 1 =] [[] put] when unwrap siblings] each] assemble [rehash] map]] [merkle [[hash node] map [count 1 >] [joiner] while]]] [["a" "b" "c" "d" "e"] count 5 ;; 2nd item swap path ] let
[1 1 1 0 1 0]
[[#b64 "FO3l6Ol62TcjJ3KPUJm5VgSjlZPKw704o0OtdiBSE+c=" [[#b64 "5aAf7hTg7VxIcU8iGA8lrYNltT+XefedxKPX6Tlj+Uo=" [[#b64 "ypeBEsobvcr6wjGzmiPcTaeG7/gUfE5yuYB3ha/uSLs=" []] [#b64 "PiPoFgA5WUoziU9lZOGxNIu9egCI1CxKy3PurtWcAJ0=" []]]] [#b64 "v/4LNNuha8b6wXwIusVdZ2ze1aSt5B/iyZJKXd6PPls=" [[#b64 "Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y=" []] [#b64 "GKw+c0PwFokMUQ6T+TUmEWnZ4/VlQ2Qpgw+vCTT0+OQ=" []]]]]]]
[1 1 1] 5 0 [[[count] shield] dive -] dip swap repeat swap join
[0 0 1 1 1]
2.4. CANCELED Make taker/dropper more flexible
Goal: implement drop and drop-while with the same logic
Canceled - the commonality between drop and drop-while are too small to be worth trying to factor out.
[1 2 3 4 5] [take] 3 [[[positive?] [[generate drop] dip dec] while [generate swap] dip float] bail] collect
[4 5] [[[positive?] [[generate drop] dip dec] while [generate swap] dip float] bail] 0 [take] []
This is what drop-while looks like
[] [take] [positive?] [] ;; the state (whether threshold reached) [[] ;; condition - whether we've finished dropping or not [[generate] divedown] ;; true - pass everything else through [[[generate] divedown] ;; prime init [[[clone] divedown execute] bail] ;; bring pred up and exec it [drop] ;; if pred passes drop the value prime ;; after this should have value on top [drop true] dip ;; set flag ] ;; false - generate, check pred, repeat if] collect
[] [[] [[generate] divedown] [[[generate] divedown] [[[clone] divedown execute] bail] [drop] prime [drop yes] dip] if] yes [positive?] [take] []