<-- back

Virtues

Documentation for Bless Revision 23/12/16


What is Bless?

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.


Limitations

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.


Basic Calls & The Stack

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


List Operations

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


Comparisons and Conditionals

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

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


Example Program

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


ᅠᅠᅠᅠᅠᅠᅠ by ⌘:

"//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


Altale:

"///////////////////////////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


SFRI.el (source):

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)))))
        

All channel redeems should be possible using bless.org:

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)


Index

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 everchanging

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.