Documentation for Bless Revision 23/12/16
Bless is a programming language that can be executed in LCOLONQ's twitch streams.
it is a stack-based, FORTH-like language that aims to maximize fun.
The stack is global, meaning it persists between calls, and you are able to access the stack someone else has left behind.
In addition to the 500 character limit for twitch, there is a fuel system to bless.
every program has 50 fuel, and every function call or variable push decrements the fuel by 1.
the program will stop once the fuel runs out. this is to protect against a program that loops forever.
Okay. let's get coding now.
You're able to run program via the run program or add hook channel point redeem (both for 100 $COLON). We'll focus on the first one and talk about hooks in a separate paragraph.
everything that isnt reserved words are pushed onto the stack. this includes numbers, strings and variable-ized-functions (closures).
1 "a" (+ 1)|push 1|1
1 "a" (+ 1)|push "a"|1 "a"
1 "a" (+ 1)|push (+ 1)|1 "a" (+ 1)
Keep in mind that you cannot push lists into the stack directly.
To push a list, use the : command.
1 2 : 3 :|push 1|1
1 2 : 3 :|push 2|1 2
1 2 : 3 :|pop 2 from stack|1 2
1 2 : 3 :|cons 2 to 1|(2 . 1)
1 2 : 3 :|push 3|(2 . 1) 3
1 2 : 3 :|pop 2 from stack|(2 . 1) 3
1 2 : 3 :|cons 3 to (2 . 1)|(3 2 . 1)
to make a proper list, there should be a [] in place of a 1 so that the rightmost element is nil.
!! As of 23/12/16, [] is "broken", and does nothing. clonk will fix this.
There are classic arithmetic operators, being +, -, * and /.
1 2 +|push 1|1
1 2 +|push 2|1 2
1 2 +|pop 2 from stack|1 2
1 2 +|push result (1+2)|3
Common stack operations are here. dup, swap and drop.
2 3 swap - dup + drop|push 2|2
2 3 swap - dup + drop|push 2|2 3
2 3 swap - dup + drop|pop 2 from stack|2 3
2 3 swap - dup + drop|push in other order|3 2
2 3 swap - dup + drop|pop 2 from stack|3 2
2 3 swap - dup + drop|push result (3-2)|1
2 3 swap - dup + drop|pop 1 from stack|1
2 3 swap - dup + drop|push twice|1 1
2 3 swap - dup + drop|pop 2 from stack|1 1
2 3 swap - dup + drop|push result (1+1)|2
2 3 swap - dup + drop|pop 1 from stack|2
Closures are represented by a list with a function in them. You can only call functions within bless, and closures can be invoked using eval.
4 2 (1 +) eval (+) eval|push 4|4
4 2 (1 +) eval (+) eval|push 2|4 2
4 2 (1 +) eval (+) eval|push (1 +)|4 2 (1 +)
4 2 (1 +) eval (+) eval|pop 1 from stack|4 2 (1 +)
4 2 (1 +) eval (+) eval|evaluate (1 +): push 1|4 2 1
4 2 (1 +) eval (+) eval|evaluate (1 +): push result (2+1)|4 3
4 2 (1 +) eval (+) eval|push (+)|4 3 (+)
4 2 (1 +) eval (+) eval|pop 1 from stack|4 3 (+)
4 2 (1 +) eval (+) eval|evaluate (+): push result (4+3)|7
After all is done, you can call print to print the result to clonk's chat.
"jetsWave" print|push "jetsWave"|"jetsWave"
"jetsWave" print|pop 1 from stack|"jetsWave"
"jetsWave" print|print to chat|
prints jetsWave
The easiest way to create a list is iota, it takes a number and generates a list of that length.
5 iota|push 5|5
5 iota|pop 1 from stack|5
5 iota|create a default list of length 5|(0 1 2 3 4)
There are also : that adds element to list, and explode that takes all elements of the list and puts them on the stack.
Keep in mind that various functions require the list to be proper. if the code doesnt work try making your list proper.
gather also exists, taking a number and trimming the stack to the topmost elements of the stack.
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|push (1 2 3 5 8)|(1 2 3 5 8)
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|pop 1 from stack|(1 2 3 5 8)
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|explode|8 5 3 2 1
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|push nil|8 5 3 2 1 nil
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|swap|8 5 3 2 nil 1
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|pop 2 from stack|8 5 3 2 nil 1
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|cons 1 nil|8 5 3 2 (1)
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|swap|8 5 3 (1) 2
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|cons 2 (1)|8 5 3 (2 1)
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|swap|8 5 (2 1) 3
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|cons 3 (2 1)|8 5 (3 2 1)
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|print|8 5 (3 2 1)
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|push 1|8 5 1
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|pop 1 from stack|8 5 1
[] 1 : 2 : 3 : 5 : 8 explode [] swap : swap : swap : print 1 gather|set stack size to 1|8 5
prints (3 2 1)
Finally, each loops over the list functional programming mapping style.
5 iota (1 +) each print|push 5|5
5 iota (1 +) each print|create a default list of length 5|(0 1 2 3 4)
5 iota (1 +) each print|push (1 +)|(0 1 2 3 4) (1 +)
5 iota (1 +) each print|pop 2 from stack|(0 1 2 3 4) (1 +)
5 iota (1 +) each print|index (0 1 2 3 4)|0
5 iota (1 +) each print|do (1 +)|0 1
5 iota (1 +) each print|do (1 +)|1
5 iota (1 +) each print|index (0 1 2 3 4)|1 1
5 iota (1 +) each print|do (1 +)|1 1 1
5 iota (1 +) each print|do (1 +)|1 2
5 iota (1 +) each print|do (1 +) over (0 1 2 3 4)|1 2 3
5 iota (1 +) each print|do (1 +) over (0 1 2 3 4)|1 2 3 4
5 iota (1 +) each print|do (1 +) over (0 1 2 3 4)|1 2 3 4 5
5 iota (1 +) each print|print|1 2 3 4 5
prints 6
each also works with binary operators, turning it into a reduce type operation.
0 5 iota (+) each print|push 0|0
0 5 iota (+) each print|push 5|0 5
0 5 iota (+) each print|iota 5|0 (0 1 2 3 4)
0 5 iota (+) each print|push (+)|0 (0 1 2 3 4) (+)
0 5 iota (+) each print|pop 2 from stack|0 (0 1 2 3 4) (+)
0 5 iota (+) each print|index (0 1 2 3 4)|0 0
0 5 iota (+) each print|do (+)|0
0 5 iota (+) each print|index (0 1 2 3 4)|0 1
0 5 iota (+) each print|do (+)|1
0 5 iota (+) each print|do (+) over (0 1 2 3 4)|3
0 5 iota (+) each print|do (+) over (0 1 2 3 4)|6
0 5 iota (+) each print|do (+) over (0 1 2 3 4)|10
0 5 iota (+) each print|print|10
prints 15
Classic lisp compare functions of =, <, >, <= and >= exists.
and if command can be used to branch programs.
!! As of 23/12/16, conditional check is "broken", and will always return true. clonk will fix this (maybe).
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|push stuff to stack|"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print)
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|push (9 10 + 21 =)|"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =)
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|pop 3 from stack|"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =)
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|evaluate (9 10 + 21 =) > #f|"What's 9 + 10?"
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|evaluate ("https://cutt.ly/9plus10is19" print) on the current stack|"What's 9 + 10?" "https://cutt.ly/9plus10is19"
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|evaluate ("https://cutt.ly/9plus10is19" print) on the current stack|"What's 9 + 10?" "https://cutt.ly/9plus10is19"
"What's 9 + 10?" (9 10 + print) ("https://cutt.ly/9plus10is19" print) (9 10 + 21 =) if drop|pop 1 from stack|"What's 9 + 10?"
prints "https://cutt.ly/9plus10is19" because the world is cruel
Hooks can be added by the add hook redeem. hooks run every time certain actions are taken within the stream, and resets every stream.
As of 23/12/16, hook is broken. clonk will fix this.
There are currently 1 hook: follow, which runs whenever someone follows the stream and the user id of that stream is pushed onto the stack before the program is run.
another command to introduce is shill, which basically runs !discord IRC.
follow drop shill|add hook to follow|"username"
follow drop shill|pop 1 from stack|"username"
follow drop shill|shill !discord IRC|
prints https://discord.gg/f4JTbgN7St
#cyberspace on IRC at colonq.computer:26697 (over TLS) every follow
You can play notes using the play command. using this, you can run multiple rows of bells of bezelea, allowing the playing of chords.
heres Gamer with basic chords as an example.
"c" "e" "g" 3 iota (drop play) each|push stuff|"c" "e" "g"
"c" "e" "g" 3 iota (drop play) each|push 3|"c" "e" "g" 3
"c" "e" "g" 3 iota (drop play) each|iota 3|"c" "e" "g" (0 1 2)
"c" "e" "g" 3 iota (drop play) each|push (drop play)|"c" "e" "g" (0 1 2) (drop play)
"c" "e" "g" 3 iota (drop play) each|pop 2 from the stack|"c" "e" "g" (0 1 2) (drop play)
"c" "e" "g" 3 iota (drop play) each|index (0 1 2)|"c" "e" "g" 0
"c" "e" "g" 3 iota (drop play) each|evaluate (drop play)|"c" "e" "g" 0
"c" "e" "g" 3 iota (drop play) each|evaluate (drop play)|"c" "e" "g"
"c" "e" "g" 3 iota (drop play) each|index (0 1 2)|"c" "e" 1
"c" "e" "g" 3 iota (drop play) each|evaluate (drop play)|"c" "e" 1
"c" "e" "g" 3 iota (drop play) each|evaluate (drop play)|"c" "e"
"c" "e" "g" 3 iota (drop play) each|index (0 1 2)|"c" 2
"c" "e" "g" 3 iota (drop play) each|evaluate (drop play)|"c" 2
"c" "e" "g" 3 iota (drop play) each|evaluate (drop play)|"c"
plays [ceg] in new bezelea notation
Each plays are done in parallel and if clonk's CPU lags in the middle of the bless execution the chords will be messed up.
Keep this in mind when making scores with layers, and keep layers to a minimum by collapsing lines.
Here are some scores using this program.
Super Idol:
"//////G#///////d/////a#/d///////////////c///////A#" "//////D#D#G#/////FFA#//A#//BB/D////GGc//d/d#G//G////FFA#///a#/d#////D#A#d#A#" "//////C/CCCCC/D/DDD/D/G/GGGGG/D#/D#D#D#/D#/D#/D#D#D#D#D#/D/DDD/D/D#D#D#D#D#FGfg" "ggg#gfgc/fd#c/d#/fA#f/gfd#fg/d#cd#/d#/c/ggg#gfd#gf/gc/cd#d/ddg/g" 4 iota (drop play) each
Plays gg[g#]gfg[CD#cG#][D#][CG#f][Cd#][Cc]C[Cd#]/[DFfd][FA#][DA#f]D[Dg][A#f][Dd#a#]f[GBgd]B[Gd#][GDc][Gd#]G[Gd#]/[D#Gc]G[D#cg][D#g][D#g#][dg][D#f][d#d#][D#Ggc]f[D#][D#Gg][D#c][D#][D#c][d#][DFdA#]F[DA#d][Dd][Dg]/[Da#g]/[D#d#][D#][D#][D#][D#][FD#][GA#][fd#][gA#]
Gamer:
"////c///c///c///////A///A///A///////A///A///G/////G" "//E/G/E/G/E/G/E/G/C/E/C/E/C/E/C/E/C/F/C/F/C/D/C/F/C" "c/e/g/g/g/agg/g/c/e/e/e/c/d/c/A/A/e/e/e/c/d/cd/eG/c" 3 iota (drop play) each
Plays
"//D#D#/D#D#D#D#D#DD/DDDDDD#D#/D#D#D#D#D#CC" "//G#G#/G#G#G#G#G#BB/BBBBBGG/GGGGGFF/CC" "ffgggfgggd#ffd#d#d/ffggga#ggffgg/FFC" 3 iota (drop play) each
Plays ff[D#G#g][D#G#g]g[D#G#f][D#G#g][D#G#g][D#G#g][D#G#d#][DBf][DBf][d#][DBd#][DBd][DB][DBf][DBf][D#Gg][D#Gg]g[D#Ga#][D#Gg][D#Gg][D#Gf][D#Gf][CFg][CFg]/[CF][CF]C
"///////////////////////////EE" "////////////////////////EEEGGE/////////D#D#D#D#D#" "//////EEE///DDDF#F#F#F#F#F#EEEGGGBBGFFFFFFFFFD#D#D#GGGGGD#" "DDDGGGGGGEEEAAAAAAAAABBBBBBddBCCCCCCAAAA#A#A#A#A#A#A#A#GFF/FF/FF" "GGABBBBBBAAGddddddBBdgggf#f#f#ggagggffgddfddddddccA#AAAA#A#A#ccc" 5 iota (drop play) each
Plays [GD][GD][AD][BG][BG][BG][BGE][BGE][BGE][AE][AE][GE][dAD][dAD][dAD][dAF#][dAF#][dAF#][BAF#][BAF#][dAF#][gBE][gBE][gBE][f#BGE][f#BGE][f#BGE][gdBGE][gdBGE][aBGE][gCF][gCF][gCF][fCF][fCF][gCF][dAF][dAF][fAF][dA#D#D#][dA#D#D#][dA#D#D#][dA#GD#][dA#GD#][dA#G][cA#G][cA#G][A#GD#][AF][AF]A[A#F][A#F]A#[cF][cF]c
Geiser Music (as seen in 23/12/16):
"C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#C#EC#C#C#C#C#EC#C#C#C#C#C#C#C#C#EC#C#C#C#C#EC#C#C#" "AEAEEAEEG#D#G#D#D#G#D#G#F#EF#EEF#EEEG#G#G#G#G#EG#G#G#G#G#EG#G#EEAAAAAEAAAAAE" "c#Ag#AAc#g#Ac#G#g#G#G#c#g#ec#F#g#F#F#c#g#F#c#bag#f#f#f#f#eed#d#BBBBc#bag#f#f#f#f#eed#d#BBBE" 3 iota (drop play) each
Plays [C#Ac#][C#EA][C#Ag#][C#EA][C#EA][C#Ac#][C#Eg#][C#EA][C#G#c#][C#D#G#][C#G#g#][C#D#G#][C#D#G#][C#G#c#][C#D#g#][C#G#e][C#F#c#][C#EF#][C#F#g#][C#EF#][C#EF#][C#F#c#][C#Eg#][C#EF#][C#Ec#][C#G#b][C#G#a][EG#g#][C#G#f#][C#G#f#][C#Ef#][C#G#f#][C#G#e][EG#e][C#G#d#][C#G#d#][C#EB][C#G#B][C#G#B][C#EB][C#Ec#][C#Ab][C#Aa][EAg#][C#Af#][C#Af#][C#Ef#][C#Af#][C#Ae][EAe][C#Ad#][C#Ad#][C#EB]BBE
Abbreviation of Super Required Free Ideas (clearly this wont have any issues) is a list of few basic control and manipulation commands that imo will be quite useful.
Update since 23/12/16: SRFI.el has been straight up copied into the contribs folder. you may use these functions now.
any and all may be a little funky and there might be changes after the next stream.
;;; prod-bless-sfri --- Super Required Free Ideas -*- lexical-binding: t; -*- ;;; Commentary: ;;; Code: (require 'fig-bless) (require 'dash) (require 's) (defvar prod-bless-sfri (list ; irreplacable (within reasonable fuel) functions (cons 'reverse (fig//bless-helper-unary 'reverse)) (cons 'concat (fig//bless-helper-binary (lambda (a b) (concat a b)))) (cons 'substring (lambda (s) (fig//bless-manage-fuel) (cons (substring (nth 2 s) (cadr s) (car s)) (nthcdr 3 s)))) (cons 'contains (fig//bless-helper-binary (lambda (a b) (s-contains? b a)))) ; car needle, cadr haystack (cons 'number (fig//bless-helper-unary 'string-to-number)) (cons 'string (fig//bless-helper-unary 'number-to-string)) (cons 'random (fig//bless-helper-unary 'random)) ; semi-replacable functions (cons 'length (fig//bless-helper-unary 'length)) (cons 'bundle (lambda (s) (fig//bless-manage-fuel) (cons (-take (car s) (-drop 1 s)) (-drop (+ (car s) 1) s)))) (cons 'split (fig//bless-helper-binary (lambda (a b) (s-split b a)))) (cons 'join (fig//bless-helper-binary (lambda (a b) (s-join b a)))) (cons 'filter (fig//bless-helper-binary (lambda (a b) (-filter b a)))) (cons 'any (fig//bless-helper-binary (lambda (a b) (-any? b a)))) (cons 'all (fig//bless-helper-binary (lambda (a b) (-all? b a)))) ; replacable (but forthy) functions (cons 'rot (lambda (s) (fig//bless-manage-fuel) (cons (-last-item s) (-butlast s)))) (cons 'over (lambda (s) (fig//bless-manage-fuel) (cons (cadr s) s)))))
Im going to assume this means every redeems under 100 points since using bless to cheat equity lord sounds wrong
mental clarity
boost/tsoob (maybe a hook?)
friend/clonk reaction
palette swap
idol dream (it'd be cool if this is like get-pfp-link so it can be used in conjunction with non-hair swaps)
forsen
various asks (feed, talk to friend)
bells play
theme change
spin / reverse polarity
intj stare
drink (you can probably just "drink water dummy" print)
Reserved Words:
(function) eval
(any) id
(function:then) (function:else) (bool) if
(list) (function) each
(list/string) length
[]
(list) (any) :
(number) iota
(list) explode
(number) gather
(number) bundle
(list) (bool) filter
(list) (bool) any
(list) (bool) all
(string) (string) concat
(string) (number:start) (number:end) substring
(string:haystack) (string:needle) contains
(string) (delimiter) split
(list) (delimiter) join
(number) string
(string) number
(number) (number) +
(number) (number) -
(number) (number) *
(number) (number) /
(number) (number) =
(number) (number) <
(number) (number) >
(number) (number) <=
(number) (number) >=
(number) random
(any) dup
(any) (any) swap
(any) drop
(any) ... (any) rot
(any) (any) over
(any) print
(any) play
shill
Hooks:
follow (follower_name)
Bless is going to be updated as long as the bit is funny. Here in LCOLONQ computer compound we value the funny bits.
I(prod) will also (probably) update this page as long as Bless updates (and I stay a clonk head).
Check back occasionally for the upcoming updates.