Keg
Paradigm(s) | imperative |
---|---|
Designed by | User:JonoCode9374 |
Appeared in | 2018 |
Memory system | Stack based |
Dimensions | One dimensional |
Computational class | Turing complete |
Major implementations | Official |
Influenced by | Fish |
File extension(s) | .keg |
Keg is a stack-based esolang with condensability as well as simplicity and readability in mind. It’s main purpose is to be used for golfing, although it can be potentially used for other purposes. What makes this esolang different from others is that:
- Alphanumerical characters are automatically pushed (no need to wrap them in quotation marks)
- There are readable and intuitive
if
statements,for
andwhile
loops - The number of functions to remember is small
- And much more
A Few Conventions of This Document
∆ ... ∆
in a code snippet means that the code in the...
is optional>
in a code snippet means an input prompt>>>
in a code snippet means a command prompt
Design Principles
The main inspiration for Keg comes from a want of an esolang where only symbols count as commands and everything else is pushed onto the stack as a literal. This is why there are only 12 functions, 7 ‘keywords’ and 8 operators. As such, this system allows for shorter programs where strings are involved (uncompressed strings in Keg are usually 1-2 bytes shorter than their counterparts in other languages).
Another design feature of Keg is the look of if
statements, for
loops and while
loops. These structures take on the form of:
B...B
Where B
is any of the three brackets ((/)
, [/]
or {/}
) and ...
is any body of code
The Basics
Most tutorials show how to print the string Hello, World!
, so that’s what this tutorial will do as well. Here is a simple 21 byte program to achieve the goal.
Hello\, World\!^(!|,)
Explanation
Hello #Push the characters "H", "e", "l", "l" and "o" to the stack \, #Escape the "," and push it to the stack World #Push the characters "W", "o", "r", "l" and "d" to the stack \! #Escape the "!" and push it to the stack ^ #Reverse the stack (!| #Start a for loop and set the count to the length of the stack , #Print the last item on the stack as a character )
In the above example, 6 new functions and keywords are introduced:
\
: Escapes the next command, and instead pushes it as a string (pushes its ASCII value)
,
: Prints the last item on the stack as a character
!
: Pushes the length of the stack onto the stack
^
: Reverses the stack
(...)
: The for loop structure
|
: Used in structures to switch from one branch to the other.
The Stack
One of the most important parts of Keg is the stack, which is where all operations are performed. A stack is a type of container (or list) where the last item in the container is the first item to be operated on (LIFO – Last In First Out). In the following examples, the stack will be investigated.
3# [3] 4# [3, 4] +# [7]
In the above example, the numbers 3
and 4
are pushed onto the stack, and are then added using the +
operator. The way it works is that the +
pops what will be called x
and y
off the stack (the first and second last item) and pushes y
+ x
back onto the stack. Note that the order of x
and y
are important when using the -
and \
operators, as x
- y
doesn’t equal y
- x
most of the time (as is the same with x
/ y
and y
/ x
). This can be seen in the following example:
34-.#Outputs -1 43-.#Outputs 1 34/.#Outputs 0.75 43/.#Outputs 1.333333333333
Note that the .
function prints the last item on the stack as an integer.
Input and Output
Keg has two output functions and one input function. When taking input from the user, the next line from the Standard Input and push the ASCII value of each character onto the stack. It will then push -1 onto the stack to sigify the end of input (input as integers will be coming in a later version of Keg). Input is taken using the ?
command, as shown in the example program:
?(!|,) # > Example text # Example text
The two output functions (.
– Print as integer and ,
– Print as string) have already been detailed in other sections
Program Flow
If
Statements
As mentioned in the introduction, Keg has a readable and intuative way of expressing if
statements, for
and while
loops. The form of an if
statement is:
[...1 ∆| ...2∆]
When an if
statement is run, the last item on the stack is popped, and if it is non-zero, ...1
is executed. If there is a |...2
, it is executed if the popped value is 0.
For
Loops
The form of a for
loop is:
(∆...1|∆ ...2)
When a for
loop is run, if ...1
is present, it will be evaluated as used as the number of times the loop will be run (if it isn’t given, the length of the stack will be used). ...2
is the body of the for
loop, which will be executed.
When ...1
is given, it is evaluated as normal Keg code, but with a few differences:
- A temporary stack is created, of which the first item is returned once the expression is finished
- Most keywords (except
&
and\
) cannot be used, and raise a syntax error !
and:
use the main stack for its values but affects the temporary stack_
pops the last item off the main stack and appends it to the temporary stack+-*/%
all apply to the temporary stack
An example of a valid expression to evaluate could be:
:91++
Which would:
- Add the last item of the main stack onto the temp stack
- Push the number 9
- Push the number 1
- Add 9 and 1 to get 10
- Add 10 and the duplicated value, and then return it, as it will be the only expression in the temp stack
While
Loops
The form of a while
loop is:
{ ∆...1|∆ ...2}
When a while
loop is run, ...1
(if given) will be the condition of the loop (if it isn’t present, 1
will be used as the condition of the loop) and ...2
will be executed until the given condition is false.
Switch
Statements
This is a part of the Keg+ expansion
Since November 2019, Keg has switch statements, which act in much the same way as C-like/Java/other-languages-that-have-switch-statements do. In Keg, one starts with a value on top of the stack, and then compares it to a series of expressions, until a suitable match is found. Here is the form of a switch in Keg:
¦<single_expression><keg_code>|<single_expression><keg_code>|...║<default_code>™
Where:
single_expression
is either a character or a stringkeg_code
is the code to run upon the expression matching the top of stackdefault_code
is an optional block to run if the top of stack doesn't match any of the provided cases
An example of a switch statement in action can be found here
User Defined Functions
One of the special features of Keg is user-defined functions, which are defined using the following form:
@name ∆n∆ | ...ƒ
Where: name
= the name of the function (note that it needs to be one full word, and that it can’t contain any @
’s) n
= the number of items popped from the stack ...
= the body of the function
If n
isn’t present, no items will be popped from the stack, and all code in the function will be applied to the main stack.
An example function would be:
@triple 1|::++ƒ
An example of calling it would be:
@tripleƒ
In a full program, it would look like so:
@triple 1|::++ƒ8@tripleƒ
Which would result in:
24
Special Bits
- If nothing is printed during the run of the program, the whole stack will be joined together (stringified, with values less than 10 or greater than 256 being treated as integers) and printed
- Closing brackets can be left out of programs, and will be auto-completed in a LIFO matter
- Input is pushed in a reversed manner (
abc123
is pushed as-1,3,2,1,c,b,a
)
Implicit Input
Hey, so Keg has implicit input now: pretty much, every time something is tried to be popped from the stack and there isn't anything to pop, the interpreter will prompt for input to make up for the lack of items. Once it receives this input, it reverses the input for usage (as most input commands are followed by
^_
Of course, it doesn't work perfectly right now, so changes are going to be made to the interpreter. But for now, the implicit input feature kind of works. Enjoy!
No EOI's after inputs
The next version of Keg does not have the annoying EOI's anymore; this helps code-golfers golf out a lot of bytes. The program above can now have 1 byte removed: ^
, as this is simply the input reversed.
Computational class
It is Turing-complete, as brainfuck can compile to it.
+: 1+ -: 1- <: ' >: " [...]: {:|...} .: , ,: No corresponding code(it does not matter)
Here is a simpler way to do that:
Volatile is an esoteric subset of Keg that was proven to be Turing-complete. All Volatile commands correspond to Keg's commands, but there are two exceptions: .: :. (...): {:|...}
Example Programs
An "improved" version of the Hello, World! program in the tutorial
\!dlroW \,olleH(,)
Hello, world!, Further Golfed
Hello\, World\!
Cat program
^
Reverse cat:
^^
Or:
:_
Or:
?
FizzBuzz Program (loops up to 100)
0(d|1+:35*%0=[ zzubzziF(9|,)|:5%0=[ zzuB(5|,)|:3%0=[ zziF(5|,)|:. ,]]])
This one loops on forever(very slowly):
0{1+:�%0=[ zzubzziF(9|,)|:5%0=[ zzuB(5|,)|:3%0=[ zziF(5|,)|:. ,]]]}
99 bottles of beer Program
c&(c|&:.& bottles of beer on the wall\, ^(,)&:.& bottles of beer\.91+^(,)Take one down\, pass it around\, ^(,)&1-:.& bottles of beer on the wall\.91+^(,))
Explanation
c& #Store 99 in the register (c| #Because the ASCII value of 'c' is 99 &:.& #Print the value in the register bottles of beer on the wall\, ^ (,) &:.& bottles of beer\.91+^ (,) Take one down\, pass it around\, ^ (,) &1- #Subtract one from the register :.& bottles of beer on the wall\.91+^ (,) )
Non-cheating variation
c&(c|&:.& bottle&:&1=[|s] of beer on the wall\, ^(,)&:.& bottle&:&1=[|s] of beer\.\ ^(,)Take one down\, pass it around\, ^(,)&1-:&[&:.&|no more] bottle&:&1=[|s] of beer on the wall\.\ ^(,))
Quine
Q
Note that quines can be of any length
Or, a non-cheating quine
`:.,`:.,
Fibonacci sequence
10{::. ,&+&$}
Explained
#Fibonacci sequence 10 #Push the first two terms onto the stack { ::. #Duplicate the top item, and then print it , #Print a space &+&$ #Direct of the ><> version of this program }
Variation
This one avoids using the accumulator:
10{::. ,'+}
Explanation
#Fibonacci sequence 10 #Push the first two terms onto the stack { ::. #Duplicate the top item, and then print it , #Print a space ' #Put the bottom of the stack to the top + #Add the "accumulator" by the second top value }
Another variation
You can repeat 1":&+
arbitrary times in this code snippet to get arbitrary fibonacci numbers.
0{1":&+:. ,}
Recursive Function
@fib 1|:0=[_0|:1=[_1|;:@fibƒ";@fibƒ+]]ƒ¿@fibƒ.
Truth-machine
:[{:.
Infinite loop(extremely trivial)
{
One-line integer input
^_(\0-")^(!1-|91+*+)
A shorter variation:
^_(\0-")^(!1-|\ *+)
" re-written in Keg
(!1-|')
' re-written in Keg
(!1-|")
_ re-written in Keg
:-+
Deadfish
0&{&:&\@4*=[&_0&]&:&0<[&_0&] \>\>25*,,,,?:o=[&:.&]:i=[&1+&]:d=[&1-&]:s=[&:*&]}
Another variation that is 10 bytes shorter:
0{'::"ÿ1+=$0<+['_0"] \>\>\ ,,,,?:o=[':."]:i=['1+"]:d=['1-"]:s=[':*"
Factorial
Outputs in floating-point integers(sadly). Can anyone improve it?
^_(\0-")^(!1-|91+*+)::&(:|&:&*&1-&)$/.
A recursive function approach:
@factorial 1|:1<[_1|:;@factorialƒ*]ƒ
Digital root calculator
^_(\0-")^(!1-|91+*+)1-9%1+
Dice simulator
~6% a dellor uoY(!1-|,).
(Note: To conform the "readable" goal:)
~6%You rolled a '^(!1-|,).
(The programs above have a chance to roll a 0. This is an improved version:)
~6%1+ a dellor uoY(!1-|,).
Looping counter
0&{&:.1+&\ ,}
Triple a number using a function
@t1|::++ƒ
Swap the words good and bad
?G=[øBad|ø‘5Ƴ
Or
‘5ƳP↫‘᠀-
Logical operators
They are quite easy to implement.
AND: x AND y is equivalent to x*y in boolean arithmetic. (If a number is larger than 0, then it should be 1.) In Keg: * OR: x OR y is equivalent to x+y in boolean arithmetic. In Keg: + NOT: NOT x is equivalent to 1-x. In Keg: 1$- XOR: x XOR y is equivalent to 1-(x==y). In Keg: =1$-
Command Glossary
Command | Description | Usage | Notes |
---|---|---|---|
!
|
Pushes the length of the stack onto the stack | !
|
|
:
|
Duplicates the last item on the stack | :
|
|
_
|
Removes the last item on the stack | _
|
|
,
|
Prints the last item on the stack as a character | ,
|
|
.
|
Prints the last item on the stack as an integer | .
|
|
?
|
Gets a line of input from the user | ?
|
Pushes -1 after the last character of input to signify EOI |
'
|
Left shifts the stack (Put the bottom of the stack to the top) | '
|
|
"
|
Right shifts the stack (Put the top of the stack to the bottom) | "
|
|
~
|
Pushes a random number onto the stack | ~
|
The number will be between 0 and 32767 |
^
|
Reverses the stack | ^
|
|
$
|
Swaps the top two items on the stack | $
|
|
#
|
Starts a comment | #
|
|
|
|
Branches to the next section of a structure | B...|...B
|
B is any one bracket type
|
\
|
Escapes the next command, and pushes it as a string | \<command>
|
|
&
|
Gets/sets the register value | &
|
|
@
|
Define/call a function | @ name ∆n∆ | ...@
|
|
+
|
Pops x and y and pushes y + x
|
<value><value>+
|
|
-
|
Pops x and y and pushes y - x
|
<value><value>-
|
|
*
|
Pops x and y and pushes y * x
|
<value><value>*
|
|
/
|
Pops x and y and pushes y / x
|
<value><value>/
|
Division by zero gives an error |
%
|
Pops x and y and pushes y %(modulo) x
|
<value><value>%
|
Division by zero gives an error |
<
|
Pops x and y and pushes y < x
|
<value><value><
|
|
>
|
Pops x and y and pushes y > x
|
<value><value>>
|
|
=
|
Pops x and y and pushes y == x
|
<value><value>=
|
|
0-9
|
Pushes the given integer onto the stack | <value>
|
|
Other
|
Pushes the ASCII value of the given character onto the stack | <value>
|
Extended command glossary (a.k.a. Reg(Restructured Golfing) )
These commands are added to Keg in order to make Keg programs shorter. These instructions can be implemented in Keg quite easily. These are NOT part of the official Keg. (From A__)
Command | Description | Usage | Notes&Implementation |
---|---|---|---|
Ï
|
Replaces the top of stack with all items from top to 0
|
Ï
|
:1-) |
;
|
Decrement the top of the stack | ;
|
1-
|
Ë
|
Exponentation | Ë
|
# Unknown
|
§
|
Sine function | §
|
# Unknown
|
¿
|
Nice input | ¿
|
Tries to eval as Float > Integer > List > String |
∂
|
Exclusive range | ∂
|
Pops x , y and z and pushes z in range(y, x)
|
•
|
Inclusive range | •
|
Pops x , y and z and pushes z in range(y, x + 1)
|
ɧ
|
Generate range | ɧ
|
Pops x and y and pushes range(y, x + 1)
|
÷
|
Item split | ÷
|
Splits the top of stack into seperate parts |
¡
|
Factorial | ¡
|
Takes the factorial of the top of the stack |
ø
|
Empties the stack | ø
|
None |
Ω
|
Prints the entire stack | Ω
|
None |
∑
|
Apply to all the stack | ∑
|
|
¬
|
Logically nots the top of the stack | ¬
|
None |
½
|
Halves the top of the stack | ½
|
None |
Keg+ - The Next Generation of Keg
That's a bit of a lie, because it's just a part of Keg.
Keg+, which was originally planned to be a completely different and seperate language, has now been rolled and merged into base Keg. Consequently, this means it is now just an extension like Reg (which has also become more official).
Over the coming weeks, expect to see some new documentation of all the new features because there is a lot of new features, including:
- The way Keg is executed (transpiled rather than interpreted)
- Strings and Stacks
- Unicode characters galore
- String compression
- A preprocessor driven by the community
- Pre-defined, built-in functions
- And more
Until then, I shall leave everyone with a reference table for all the new Keg+ stuff.
Command | Description | Usage | Notes | Implemented? |
---|---|---|---|---|
‡ | Reads the source code until a non-number character is found | ‡<number> | Non-number character means that it isn't a valid float/integer | No |
ℤℝ⅍℠ⁿ | Converts the top of the stack to the desired type (integer, float, stack, string, character respectively) | <type> | Yes | |
⟰⟱⟷ | Takes the top of the stack and uppercases it, lowercases it or togglecases it respectively | <mode> | Doesn't do anything to non-strings | Yes |
² | Squares the top of the stack | <expr>² | Performs `top * top` | Yes |
᠀ | Take input as a string | ᠀ | Yes | |
∀ | Pushes 1 if everything on the stack is true, otherwise 0 | ∀ | Doesn't pop things from the stack | Yes |
≌ | Like above, but if everything is the same | ≌ | Yes | |
⅀ | Summates the entire stack | ⅀ | Pretty much just `∑+)` | Yes |
ß | Takes the top of the stack and executes it as Keg code | ß | Kind of | |
© | Get the value of a variable | ©name | `name` has to only contain letters | Yes |
® | Set the value of a variable to the top of the stack (popping it) | ®name | Same as above | Yes |
External Resources / Reference Implementation
- Official Github Repository (Python)
- Try It Online - Keg
- 100 exercises to improve one's Keg skills (WIP)
See also
- Keg/Golfing
- Keg Chat Room (Stack Exchange, need at least 20 rep to talk
- Answers using Keg
- Ekg - Keg, but it's for some reason more infixier and what the cool kids call "tacit" (I think)