Rif  L:   a playing card stack language
1 Introduction
1.1 Card Notation
1.2 Cards as Numbers
1.3 Decks
1.4 Arguments
1.4.1 Instructions
1.4.2 Postfix Notation
1.5 The Stack
1.6 Structure of Code
1.7 Writing Rif  L Code
1.8 Debugging
1.9 Physically Running
2 Data
2.1 Leading Suit
2.2 Jokers
2.3 Interpretations
2.3.1 Cards
2.3.2 Name
2.3.3 Integer
2.3.4 Real Number
2.3.5 Boolean
2.3.6 Character
3 Royal
3.1 Instruction Notation
3.2 Jacks
3.2.1 Js
3.2.2 Jc
3.2.3 Jh
3.2.4 Jd
3.3 Queens
3.3.1 Qs
3.3.2 Qc
3.3.3 Qh
3.3.4 Qd
3.4 Kings
3.4.1 Ks
3.4.2 Kc
3.4.3 Kh
3.4.4 Kd
4 Extras
4.1 Program Examples
4.1.1 Hello World!
4.1.2 Truth Machine
4.1.3 Fibonacci
4.1.4 Quine
4.1.5 Brainfuck
4.2 Development
4.3 Aknowledgments
8.12

RifL: a playing card stack language🔗ℹ

Jesse P. Hamlin-Navias

 #lang RifL package: RifL

RifL is a tactile auto-imperative esoteric coding language.

Tactile means that RifL can be fully represented with real-world objects: RifL is written in playing cards. You can spread cards out on a table and perform RifL code by hand.

Auto-imperative means that RifL code represents a state, and then augments its own state. The cards encode information and can also encode instruction to transform that information.

Esoteric means that the language is not meant for practical use. RifL is intended as a educational tool, to teach to students who learn best physically. It is also meant as an affordable method of introducing programming concepts. RifL can help teach computer memory and algorithms.

If you wish to run RifL code physically, you will need a bunch of decks of cards (they don’t need to all be the same brand, size, or even complete decks, just make sure you have Jokers), as well as masking tape, a sharpie, a coin or token, and the documentation below.

The first chapter, Introduction, teaches you how to read, write, and execute RifL code both physically and on a computer. The second chapter, Data, explains how RifL turns cards into numbers, words, and references. The third chapter, Royal, thoroughly covers how RifL can manipulate that data. The final chapter, Extras, has RifL code examples, past and future development information, and acknowledgements.

1 Introduction🔗ℹ

The best way to start learning RifL is from a top down view. You will need to be familiar with a 52 card deck (along with Jokers), so if you are unfamiliar, go and grab one now and look through it. This chapter overviews how RifL operates, and teaches you to read, write, and execute RifL code both physically and on a computer.

1.1 Card Notation🔗ℹ

To write and read RifL code, a notation system for cards is needed. All cards have a pip value, followed by a suit letter (except for Jokers which have no suit). The pips are:

Pip

  

Ace

  

2

  

3

  

4

  

5

  

6

  

7

  

8

  

9

  

10

  

Jack

  

Queen

  

King

  

Joker

Symbol

  

A

  

2

  

3

  

4

  

5

  

6

  

7

  

8

  

9

  

10

  

J

  

Q

  

K

  

R

The four suits are:

Suit

  

spades

  

clubs

  

hearts

  

diamonds

Symbol

  

s

  

c

  

h

  

d

Some example cards:

As > The Ace of Spades

10d > The Ten of Diamonds

Aces can also be written as 1, and Tens can be written as 0. This documentation will default to using 1 for aces, and 0 for tens, so keep this in mind when reading further.

1s > The Ace of Spades

0d > The Ten of Diamonds

All of the cards we have discussed so far as face-up. Cards in RifL can also be face-down. Face-down cards are written with a F in front.

FJc > The face-down Jack of Clubs

F0d > The face-down Ten of Diamonds

A face-down Joker can be written as FR, or shorthanded as just F. This documentation will default to writing a face-down Joker as F.

FR > A face-down Joker

F  > Also a face-down Joker

Most of the time RifL code does not rely on the value of face-down cards, so it’s ok to just write F whenever we need a face-down card. When running RifL physically, in most cases you can use whatever extra cards you have as face-down cards, except in special cases where the Kh is used.

1.2 Cards as Numbers🔗ℹ

RifL represents numbers using the number cards, that is from Aces to tens. Aces will represent the digit 1, Two cards the digit 2, and so on. However Ten cards will represent the digit 0. The cards are laid out left to right, with the rightmost card representing the ones places, the second card the tens place, the third card the hundreds place, and so on.

1s 2s > 12, the number twelve

1s 2s 3s > 123, the number one-hundred and twenty-three

9s 0s > 90, the number ninety

Leading zeros can be ignored.

0s > 0

0s 6s > 6

0s 5s 0s 6s > 506

0s 0s > 0

1.3 Decks🔗ℹ

RifL code is separated into decks of cards, with the top card written at the left, and the bottom card written on the right.

5s, 0s, 6s

In this deck, the Five of spades is the top card, the Six of spades is the bottom card. This deck has one argument, the number 506.

Each deck has a name, written as a series of cards, followed by a ":". The cards in a deck’s name must all be of the same suit, and a deck’s name cannot use leading zeros, with the exception of a name that is a single zero. The name must all be written on the same line. The name of a deck can be thought of as a number and a suit.

#lang RifL
0s: 5s, 0s, 6s > The zero spade deck, with the number 506 in it
1s: 0s, 6s > The 1 spade deck, with the number 6 in it
3s 2s: 4s, 6s > The 32 spade deck, with the number 46 in it

Within the naming restrictions, each deck’s name is up to the programmer, but no two decks in a RifL program can have the same name. It is standard to start at low deck numbers and proceed upwards as needed.

1.4 Arguments🔗ℹ

Decks can have multiple arguments, each separated by face-down cards. Face-down cards work much the same way the spaces between words and numbers work, signifying an end to one piece of information and the beginning of the next.

#lang RifL
0s: 5s, F, 0s, F, 6s

In this zero spade deck, the Five of spades is the top card, the Six of spades is the bottom card. This deck represents the number 5, followed by the number 0, followed by the number 6. This deck is not the number 506, but three separate and distinct arguments.

The number of face-down cards between arguments does not matter unless your code uses the Kh. The following two decks are essentially identical:

#lang RifL
0s: 5s, F, 0s, F, 6s
1s: F, 5s, F, F, F, 0s, F, F, 6s F, F

Each argument is either:

Data is a specific type of argument; either a sequence of number cards, or a single Joker. Each data argument can be interpreted in different ways, depending on the context.

Royal Cards and Jokers are special in regards to spacing. They don’t need face-down cards between them and other arguments. The following two decks are essentially identical:

#lang RifL
0s: 5s, F, R, F, R, F, Ks, F, Qc, F, 1s
1s: 5s, R, R, Ks, Qc, 1s

Face-down cards between Jokers and Royal cards is optional, however it is almost always best practice to separate everything out with face-down cards, but when the Kh is later covered, this flexibility will become useful.

1.4.1 Instructions🔗ℹ

Royal cards, that is Jacks, Queens and Kings, are instructions to manipulate information in decks. RifL resolves these instructions from the top of a deck to the bottom.

To illustrate this, the Qc will stand as an example. The Qc is the math Royal card, used to add, subtract, multiply, and divide numbers. Subtracting the number 3 from 5 in RifL looks as follows:

#lang RifL
0s: 5s F 3s F 1c F Qc

The Qc takes three data arguments. From the top of the 0s deck to bottom, the Qc interprets the first two arguments are numbers (5 and 3 in this example), while the third argument’s pip is ignored and only the suit matters (clubs in this example). This third argument determines if the Qc adds, subtracts, multiplies, or divides the first two arguments. A club tells the Qc to subtract.

#lang RifL
0s: 5s F 3s F 1c F Qc > Represents 5 - 3

Each Royal card requires a certain number of data arguments. Royal cards can never use other Royal cards as their arguments. The arguments given to a Royal card will always be data: either a series of number cards, or a single Joker.

1.4.2 Postfix Notation🔗ℹ

The logical operators most people are familiar with are written in Infix Notation. RifL is coded in what is known as Postfix Notation. In Postfix, the operators are written after the operands.

Infix

  

Postfix

5 - 3

  

5 3 -

2 * 5 - 3

  

2 5 * 3 -

13 - (2 * 5)

  

13 2 5 * -

This system may feel unintuitive at first, but it is very useful. It is always clear in postfix notation the order of operations. With infix notation, parentheses are needed to clarify if the order is different than reading left to right. Postfix never encounters this problem, and so it is much better for writing code.

The Qc interprets a heart in its third argument as multiplication, so the above three examples written in RifL look like this:

#lang RifL
0s: 5s F 3s F 1c Qc > 5 3 -
1s: 2s F 5s F 1h Qc F 3s F 1c Qc > 2 5 * 3 -
2s: 1s 3s F 2s F 5s F 1h Qc F 1c Qc > 13 2 5 * -

1.5 The Stack🔗ℹ

To resolve instructionss, RifL uses a special deck called the stack. Programmers can’t write code in the stack, its only used durring run time. When run, RifL proceeds in steps. Each step, RifL looks at the top of the current deck, and if it is not a Royal card, puts that card on top of the stack. If the top card of the current deck is a Royal card, RifL pulls arguments from the top of the stack to fill the Royal card’s needed arguments, and then follows that Royal card’s instructionss. After following the Royal’s instructionss, none of the used arguments nor the Royal card goes on top of the stack. RifL would process 5 - 3 as follows:

>Stack:  > Starts empty
0s: 5s F 3s F 1c Qc
 
> Step 1
>Stack: 5s
0s: F 3s F 1c Qc
 
> Step 2
>Stack: F 5s
0s: 3s F 1c Qc
 
> Step 3
>Stack: 3s F 5s
0s: F 1c Qc
 
> Step 4
>Stack: F 3s F 5s
0s: 1c Qc
 
> Step 5
>Stack: 1c F 3s F 5s
0s: Qc
 
> Step 6
>Stack: 2s
0s:  > Empty

The Qc inserts the answer, 2, back onto the stack. RifL stops running when its current deck is empty. Notice how the stack holds the arguments in backwards order. When the Qc is at the top of the current deck, RifL retrieves the first three pieces of information from the stack, and reverses them. For this reason, multi-digit numbers are reversed in the stack.

13 - (2 * 5) would resolve like this:

>Stack: > Starts Empty
2s: 1s 3s F 2s F 5s F 1h Qc F 1c Qc
 
> Step 8
>Stack: 1h F 5s F 2s F 3s 1s
2s: Qc F 1c Qc
 
> Step 9
>Stack: 0s 1s F 3s 1s > The number 10 then the number 13
2s: F 1c Qc
 
> Step 11
>Stack: 1c F 0s 1s F 3s 1s
2s: Qc
 
> Step 12
>Stack: 3s > the number 3
2s: > Empty

Notice how the top Qc resolves before the bottom Qc. The top Qc never goes into the stack, and as such, is not used as an argument for the bottom Qc. Instead, The result of the top Qc, ten (5 * 2), is used as an argument for the bottom Qc.

1.6 Structure of Code🔗ℹ

The decks are laid on a table, with the following structure:

Each space on the table is a deck name, starting at 0 on the bottom row and increasing indefinitely upwards. Each deck is given its name based on which space of the table it occupies. Spaces on the table are empty by default until a deck is put there.

#lang RifL
0s: 5s 0s 6s > This deck is in the bottom left space of the table
1s: > This deck is one above the 0s deck
0c: > This deck is one space to the right of the 0s deck

When running RifL code, the pointer determines the current deck. The current deck is the deck which RifL pulls from the top of. The pointer always starts at the 0s deck, and can change over the runtime of a RifL program. If the table starts with an empty 0s deck, the program will immediately terminate, since RifL programs end when the current deck is empty.

Some Royal cards can refer not only to decks in the table, but also the stack. The stack has the card reference R. The Royal card specifications later in the documentation will always declare if Royal cards that refer to decks can refer to the stack.

1.7 Writing RifL Code🔗ℹ

When writing RifL, each non-empty deck will have its name, followed by a colon, followed by the cards in that deck from top to bottom:

#lang RifL
0s: 2c, 4c, Js       > The deck zero of spades, with some cards in it
2c 4c: 1d, F, 1s, Jd > The deck 24 of clubs, with some cards in it

Cards can optionally have a comma after them, depending if you find that more readable.

Decks can be broken up into any number of lines, but a new deck must always start on a new line, and a deck’s name, including the colon, must all be on the same line.

0s: 1s 3s F 2s F 5s > The number 13, 2, 5
    F 1h Qc > Multiply
    F 1c Qc > Subtract
1s: R R R   > The 1 of spades deck

Anything that follows a > will not be read by the RifL executor, until either a line break or a <. These are called comments. Anything between a ( and a ) is also a comment.

#lang RifL
>This is a comment
0s: 3c >That was a deck
>This is also a comment< 1s: 3c >That was a deck
(This
is also
a comment)

1.8 Debugging🔗ℹ

If you are running RifL digitally, it can sometimes be hard to figure out what is going wrong when your code is not behaving as expected. Three debugging modes have been included to help with this. To use one of these modes, at the beginning of the RifL code (after "#lang RifL" but before any decks), you can type any of the following:

step-by-step

royal-by-royal

end-state

Step by step will print out the RifL table after every step of running the code, or when RifL encounters an error. This is the most costly of the debugging modes.

Royal by royal will print out the RifL table when the top card of the current deck is a Royal card, after the the last step, or when RifL encounters an error.

End state will print out the RifL table after the last step or when RifL encounters an error. This is the least costly of the debugging modes.

If you have multiple debugging modes enabled, they must be written in the order shown above. Anytime multiple debugging modes would print the RifL table at the same time, the RifL table is only printed once. Commenting out a debugging mode turns it off.

1.9 Physically Running🔗ℹ

All the same rules of RifL apply when running RifL physically. A good way to run RifL by hand is to draw the table out on a large piece of paper, or take masking tape to mark out the grid of the table, and a sharpie to write the name of each grid space that you delineate on the masking tape. Grid spaces need to be large enough to place decks of cards onto. You’ll need a space to one side of the grid to use as your stack. Additionally, a token of some sort is useful to mark which grid space the pointer is at. Finally, you will need the list of what each Royal card does.

To begin, set up all the cards in the code in their corresponding deck spaces. Place the token on the 0s deck space. Most RifL programs will need extra sets of cards, so keep a handful of decks ready. When running physically, Face-down cards can be any card, unless the code you are running uses the Kh.

At each step of RifL, take the top card of the deck the pointer is at, and put it on top of the stack. If the top card of the pointer deck is a Royal card, instead look up how many arguments it needs. One by one take cards from the top of the stack, and put them on top of a temporary pile. Do this until you get the required number of arguments for the Royal card, and the top card of the stack is a face-down card, a Joker, or the stack is empty. Then follow the instructionss of the Royal card. Once you are done following the instructionss, take the Royal card and any cards in that temporary pile and put them in a discard to the side.

If at any time a Royal card requires an argument from the stack, and there are no more arguments in the stack, or the wrong kind of arguments, the code has hit an error and the code stops. If at any time a Royal card makes its way into the stack, the code hits an error and stops.

2 Data🔗ℹ

RifL code is broken up into arguments. Each argument is either:

Data is a specific type of argument; either a sequence of number cards, or a single Joker. Each data argument can be interpreted in different ways, depending on the context. This chapter will cover all the different ways data can be interpreted, as well as a guide to the most common contexts in which that interpretation will happen.

2.1 Leading Suit🔗ℹ

Many Royal cards rely on the suit of a data argument. However, a sequence of number cards can have different suits in it:

0s 1c 2h 3d

To resolve this, when the documentation refers to the suit of a sequence of number cards, the suit of the top card of the sequence is all that matters. In the above example, the suit of the sequence would be spades, since the top cards is 0s.

A detail to remember is that arguments that go into the stack get reversed. To account for this, the leading suit of an argument in the stack is determined by the bottom card of the sequence, not the top.

2.2 Jokers🔗ℹ

Jokers, like the number cards, represent information, but are wild cards, and are interpreted differently in different contexts, and are not valid in all contexts. Jokers is somewhat comparable to the ’null value found in other programming languages, although that comparison sells short the usefulness of the Joker.

Jokers act like a 5th suit. When the documentation uses the suit of an argument, the interpretation of a Joker will also be listed. Sometimes a Joker in certain contexts will result in an error, which stops the code from running

2.3 Interpretations🔗ℹ

2.3.1 Cards🔗ℹ

This is the default interpretation if none is listed. No interpretation is made. The argument is taken literally as the cards in the sequence. This is most often used when the suit of an argument is the only thing that matters.

2.3.2 Name🔗ℹ

Interprets the card sequence as the name of a deck space on the table. The sequence R represents the stack. Name interpretations are either stack inclusive and will accept R, others are stack exclusive and will not accept R.

1s > the 1 of spades deck

2c 0c 3c > the 203 of clubs deck

R > the stack

A card sequence that has more than one suit type in it is invalid for a name. A card sequence that starts with a ten card is invalid for a name, unless the sequence is a single ten card.

2c 0s 3s > error

0s 1s > error

0s 0s > error

0s > 0 of spades deck

2.3.3 Integer🔗ℹ

Interprets the card sequence as a zero or positive whole number, unless the leading suit is clubs, in which case the number is a negative zero or negative whole number.

3s > 3

3c > -3

3h > 3

3d > 3

0s 4c > 4

0c 4s > -4

0s > 0

0c > -0

R is invalid for Integers.

R > error

When converting integers into cards, RifL converts zero and positive integers into all spades, but converts negative numbers into all clubs.

2.3.4 Real Number🔗ℹ

Interprets the card sequence as zero or a positive whole number, unless the leading suit is spades or clubs, and the suit of a card in the sequence is diamonds. In that case, the first diamonds card represents the decimal point (and not a digit), and all cards after the first diamonds card are the fractional part of the number. If the leading suit of a real number is clubs, the number is negative.

3s > 3

3s 0d > 3

3s 0d 0s > 3

3s 0d 1s 4s 1s 5s 9s > 3.14159

3c 0d 1c 4c 1c 5c 9c > -3.14159

3h 0d 1h 4h 1h 5h 9h > 3,014,159

3d 0d 1d 4d 1d 5d 9d > 3,014,159

0s 0d 1c             > 0.1

0s 0d 0d 1c          > 0.01

0d 0d 1c             > 1

R is invalid for a real number.

R > error

When converting numbers into cards, RifL always converts whole numbers into the Integer card form. Positive non-whole numbers get converted into spades, with the decimal point being a 0d. Negative non-whole numbers get converted into clubs, with the decimal point being a 0d.

2.3.5 Boolean🔗ℹ

The 0d, and any data argument with only tens cards that has a leading suit of diamonds evaluates as #false. R evaluates as null. All other arguments evalutate as #true.

0s > #t

0c > #t

0h > #t

0d > #f

0d 0s 0h 0c > #f

0d 0s 0h 1c > #t

1d > #t

R  > null

When converting booleans into cards, RifL converts true into 1d, and false into 0d.

2.3.6 Character🔗ℹ

Interprets the argument as zero or a positive whole number, and uses that number to reference the ASCII.

6h 5h > 'A'

1h 2h 2h > 'z'

Inteprets R as no character.

R > ''

Character interpretation is only used with card sequences that have a leading suit of hearts, or with Jokers.

When converting characters into cards, RifL converts the character into its ASCII number, and then turns that number into a hearts sequence.

3 Royal🔗ℹ

3.1 Instruction Notation🔗ℹ

Each Royal card below lists its form, which shows the number of arguments it takes, and gives each argument a name. Named arguments are written between square brackets.

After the form, the instructions, that is the digital/physical process to follow is listed. argument might be written with data types before them, which is an instruction to convert the argument into that data type.

Anytime an argument gets put on top of the stack, the argument must first be reversed in order.

3.2 Jacks🔗ℹ

3.2.1 Js🔗ℹ

Form: [Deck], Js

Instruction: Move the pointer to [Name (stack exclusive) Deck].

3.2.2 Jc🔗ℹ

Form: [X], [Y], Jc

Instruction: Starting at the current deck space, count to the right [Integer X] times, and up [Integer Y] times. Diamonds wrap around to spades. Negative [Integer X] moves left. Negative [Integer Y] moves down. Push the name of the landed on deck space onto the stack. If the landed on deck space is below the bottom row of the table, throw an error.

3.2.3 Jh🔗ℹ

Form: [Deck], Jh

Instruction: Count the number of arguments of [Name (stack inclusive) Deck]. Turn that integer into cards, and put it on top of the stack.

3.2.4 Jd🔗ℹ

Form: [Deck], [Operation], Jd

Instruction: The leading suit of [Operation] changes the function.

Spades: Print Cards Output the [Name (stack inclusive) Deck] as a list of cards. Outputting a deck does not change it.

Clubs: Print Data Output the [Name (stack inclusive) Deck] as interpreted data. If the named deck is the stack, it gets outputted in reversed order. Data with the leading suit spades or clubs gets interpreted as a real number. Data with the leading suit hearts and Jokers gets interpreted as a character. Data with the leading suit diamonds gets interpreted as a boolean. Royal cards do not get outputted. Outputting a deck does not change it.

Hearts: Read Cards Take an input of cards and puts it on top of the [Name (stack inclusive) Deck]. If the named deck is the stack, reverse the inputted cards before putting them on top of the stack.

Diamonds: Read Data Take an input of characters, and transform it into cards, and put it on top of the named deck. If the named deck is the stack, reverse the cards before putting it on top of the stack. FR is put between each datum read in.

However, there are special strings of characters that do not get interpreted as characters:

Joker: Error

This card is likely to be updated in the future. Use tens cards for [Operation] for future proofing.

3.3 Queens🔗ℹ

3.3.1 Qs🔗ℹ

Form: [A], [B], [Operation] Qs

Instruction: The leading suit of [Operation] changes the function.

Spades: Greater-than/OR: If [A] & [B] have the same leading suit, put the larger of [Real A] & [Real B] onto stack. If they are both equal to 0, the one with less cards is the larger value.

If [A] & [B] have different leading suits, put the one with the "larger" leading suit. spades > clubs > hearts > diamonds > Jokers

Clubs: Less-than/AND: If [A] & [B] have the same leading suit, put the smaller of [Real A] & [Real B] onto stack. If they are both equal to 0, the one with more cards is the smaller value.

If [A] & [B] have different leading suits, put the one with the "smaller" leading suit. spades > clubs > hearts > diamonds > Jokers

Hearts: Equal/XNOR: If [A] is exactly the same as [B], put [A] on top of the stack. Otherwise, put 0d on top of the stack.

Diamonds: Equivalent/NOT: If both [Boolean A] & [Boolean B] are false, put Ad on top of the stack. Otherwise, if [Integer A] is the same as [Integer B], put [A] on top of the stack. Otherwise, put 0d on top of the stack.

Joker: Error

3.3.2 Qc🔗ℹ

Form: [A], [B], [Operation] Qc

Instruction: The leading suit of [Operation] changes the function.

Spades: Add: Put [Real A] + [Real B] on top of the stack.

Clubs: Subtract: Put [Real A] - [Real B] on top of the stack.

Hearts: Multiply: Put [Real A] * [Real B] on top of the stack.

Diamonds: Divide: Put [Real A] / [Real B] on top of the stack. If [Real B] is zero, throw an error.

Joker: Concatenate: Put [A] on top of the stack, then put [B] on top of the stack. Do not put any face-down cards between them.

3.3.3 Qh🔗ℹ

Form: [A], [B], [Proposition] Qh

Instruction: If [Boolean Proposition] is #t, put [A] on top of the stack. If [Boolean Proposition] is #f, put [B] on top of the stack. If [Boolean Proposition] is null, do nothing.

3.3.4 Qd🔗ℹ

Form: [Sequence], [Modifier] Qd

Instruction: If [Sequence] or [Modifier] is a Joker, throw an error. Otherwise, make a copy of [Sequence], except the suit of every card in the copy of [Sequence] is the same as the leading suit of [Modifier]. Put the copy of [Sequence] on top of the stack.

This card is likely to be updated in the future, such that [Modifier] had multiple functions. Use tens cards for [Modifier] for future proofing.

3.4 Kings🔗ℹ

3.4.1 Ks🔗ℹ

Form: [Origin], [Destination], [Operation] Ks

Instruction: Find the [Integer Operation] argument of [Name (stack inclusive) Origin]. If there are not enough arguments in [Name (stack inclusive) Origin], throw an error. The leading suit of [Operation] changes the function.

Spades: Copy One: If [Destination] is a Joker, do nothing. Otherwise copy the found argument and the face-down cards directly below it and put it on top of [Name (stack exclusive) Destination]. If [Name (stack inclusive) Origin] is the stack, instead copy the found argument and the face-down cards directly above it, reverse all of those cards, and put it on top of [Name (stack exclusive) Destination].

Clubs: Copy Up To: If [Destination] is a Joker, do nothing. Otherwise, copy all the cards above and including the found argument, and put it on top of [Name (stack exclusive Destination]. If [Name (stack inclusive) Origin] is the stack, reverse all of those cards before putting it on top of [Name (stack exclusive Destination].

Hearts: Move One: Remove the the found argument and the face-down cards directly below it from [Name (stack inclusive) Origin]: if [Destination] is a Joker, the removed cards go nowhere, otherwise put them on top of [Name (stack exclusive) Destination]. If [Name (stack inclusive) Origin] is the stack, reverse the found cards before moving them.

Diamonds: Move Up To: Remove all the cards above and including the found argument, as well as the face down cards directly below it. If [Destination] is a Joker, the removed cards go nowhere, otherwise put them on top of [Name (stack exclusive) Destination]. If [Name (stack inclusive) Origin] is the stack, reverse all of those cards before putting them on top of [Name (stack exclusive) Destination].

Joker: Copy Whole: If [Destination] is a Joker, delete [Name (stack inclusive) Origin]. Otherwise copy [Name (stack inclusive) Origin] and put it on top of [Name (stack exclusive) Destination]. If [Name (stack inclusive) Origin] is the stack, reverse the copy before putting in on top of [Name (stack exclusive) Destination]

3.4.2 Kc🔗ℹ

Currently does nothing. Will be added in the future.

3.4.3 Kh🔗ℹ

Form: [Deck], Kh

Instruction: Flip [Name (stack inclusive) Deck] over.

3.4.4 Kd🔗ℹ

Form: [Deck], Kd

Instruction: Shuffle [Name (stack inclusive) Deck].

4 Extras🔗ℹ

4.1 Program Examples🔗ℹ

The programs below use both the ’1’ form of aces as well as the ’A’ form, and the ’0’ form of tens as well as the ’10’ form, depending on the programer’s preferences.

4.1.1 Hello World!🔗ℹ

Prints out "Hello World!"
#lang RifL
 
0s: 3h 3h F Ah 10h 10h F Ah 10h 8h F Ah Ah 4h F Ah Ah Ah F 8h 7h F > "!dlroW"
    3h 2h F > space
    Ah Ah Ah F Ah 10h 8h F Ah 10h 8h F Ah 10h Ah F 7h 2h > "olleh"
    F R F Ac Jd

4.1.2 Truth Machine🔗ℹ

Takes an input. If input starts with 0 or #f, print input & terminate. Otherwise print input infinitely.

This example uses the Kh. The last three lines of the program are actually two functions in one, based on if the 10s deck is flipped or not.
#lang RifL
 
>If input starts with 0 or #f, print input & terminate. Otherwise print input infinitley.
10s: R F, 10s, F, >Results of if statement
       10d, F, >for concatenation
         2c, F, Ad, Jd             >Take data input onto 2c
         2c, F, 10s, F, 10s, Ks    >Copy top arg 2c onto 10s
      >10d, F, input,< R, Qc   >Concat 10d + input
    >R F, 10s, F, 10d, input,< Qh  >If top arg input is not 0, 10s. Else R.
    >R or 10s< Kh                  > flip either deck 10s or R
    >If below section is flipped, prints out deck 2c and terminates
     10s, FJd, 10s, R, Ks > Copy 10s deck onto 10s deck
     2c, FAc, Ac, Jd      > Print out deck 2c
     10s, F2c, 10s, R, Ks > Copy 10s deck onto 10s deck

4.1.3 Fibonacci🔗ℹ

Takes a positive whole number input, and outputs the nth number of the Fibonacci sequence, where n0 = 0 and n1=1.
#lang RifL
 
0s: 2c, F Ad, Jd > input data to 2c
    Ah, F, 0s, R Ks > copy Ah onto 0s
 
Ac: 0s, F, 1s, F > 0th and 1st term of Fib
 
2c: >input deck
 
Ah: >(if input less than 2)
    Ad, F, 2d, F, > load if results
    2c, F 0s, R Ks > copy input to 0s
    >input< F 1s, F, As, Qs > greater of input and 1
    >result< F, 1s, F, Ad Qs > is input less than 2?
    >Ad, F, 2d, F, result< Qh >if result, Ad, else 2d
    >result< F, 0s R Ks > copy result deck onto 0s
 
Ad: >(true case: print result)
    Ac, F, 0s, F, > load for Ks
    2c, F, 0s, R, Ks > copy input to 0s
    >Ac, F, 0s, F, input< Ks > get input arg of Ac onto 0s
    R, Ac, Jd > print out input arg of Ac
 
2d: Ac, F, 3c, F, 1s Ks > copy 2nd args of Ac onto deck 3c
    Ac, F, 0s, F, 1d Ks > move full 2s onto 0s
    >2s args< F, As, Qc > add args of 2s together
    F, R, Ac F 0h Ks > move result onto Ac
    3c, F, Ac, F, 0h, Ks > move 3s onto 2s
    2c, F, 0s, F, 0h, Ks > move input to 0s
    >input< F, 1s, F Ac Qc > input - 1
    R, 2c, F, 0h, Ks > move result onto 2c
    Ah, F, 0s, R Ks > copy Ah onto 0s

4.1.4 Quine🔗ℹ

A RifL program that prints out itself (ignoring "#lang RifL").
#lang RifL
10s: 10s FR As R Ks As FR 2s FR 2d Ad Ks As FR 2s R Ks 2s FR As R Ks 3h 2h FR 5h 8h FR Ah Ah 5h FR As 10s FR R Ac Jd As FR As Jd 10s FR As R Ks

4.1.5 Brainfuck🔗ℹ

An interpreter for the esoteric language Brainfuck. It has unlimited cells, but does not have negative cells. Each cell is 8bit with wrap around, meaning it can input and output the unicode characters from 0 to 255. Because of RifL’s strange data input interpretation (which will receive updates in the future), numbers and the strings "#t" or "#f" may cause undefined behavior. The interpreter can take multiple input characters at a time, and will only ask for a new input when it has run out of inputted characters to use. EOF inputs result in no change to the current cell.

#lang RifL
>Brainfuck
 
>cells
0s: 0c, Js, 0s > Move to 0c as starting deck, initilize cell 0 with 0s
As: 0s > initialize cell 1 with 0s
 
>parsing------------------------------------------------
(
        \/<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        \/         ^                            ^        ^       ^
10c <- 0c/Ac -> 2c"+,-." -> 3c"[" -> 5c"]" -> 7c"<" -> 8c">" -> 9c'other'
         ^                    \/     \/
         ^                    4c     6c
         ^                    \/     \/
         ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
)
 
(first-time parse control: Inputs bf code, initializes code size & code index = 0
                           And if code is larger than 0, go to parse loop control.              )
0c: 4d, F, Ad, Jd > new start, take data input
    >If code index = code size, stop
    1c 0c, F, 2c, F,> load if results
    4d, Jh > get code size
    R, 3d, F, 0s Ks > copy code size to 3d
    F, 2d, F, 0c, R Ks > copy code index to here
    >code size F code index< F Ad Qs > code size = code index equivilant
    >0c, F, 2c, F, (index=size)< Qh
    >0c or 2c< F, 0c, R Ks > copy 2c onto 0c if code index is less than code size
 
(parse loop control: ++code-index,
                     if code-index < code-size, check +,-.          )
Ac: >If code index = code size, stop
    1c 0c, F, 2c F> load if results
    2d, F, 0c, F 0h, Ks > move code index here
    >code index,< F, As, F, As, Qc > code index + 1
    F, R, 2d, F, 0s, Ks > copy code index + 1 to 2d
    F 3d, F, 0c, R Ks > copy code size to here
    >index F code size< F Ad Qs > code index = code size equivilant
    >0c, F, 2c, F, (index=size)< Qh
    >0c or 2c< F, 0c, R Ks > copy 2c onto here if code index is less than code size
 
(check +,-. : If character at code-index in code is +,-.
              goto parse loop control, else goto check [                  )
2c: Ac, F, 3c, F > load if
    4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
    >cur char< F, 4h 3h, F, Ac Qs> lesser of 43 and cur char
    >result< F, 4h 3h, F, Ah, Qs > greater or equal to 43
    F,
    4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
    >cur char< F, 4h 6h, F, As Qs> greater of 46 and cur char
    >result< F, 4h 6h, F, Ah, Qs > less than or equal to 46
    >greater or equal 43< >F< >less or equal 46< F, Ac Qs> AND
    >Ac, F, 3c,< >Ad or 0d< Qh > if cur char is between, Ac, else 3c
    >Ac or 3c< F, 0c, R, Ks > copy Ac or 3c onto 0c
 
(check [ : If character at code-index in code is [
           go to handle [, else goto check ]             )
3c: 4c, F, 5c, F, > load if
    4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
    F, 9h 1h, F, Ah, Qs > cur char == 91
    >4c, F, 5c, F,< >91 or 0d< Qh > if cur char == 91 4c, else 5c
    >4c or 5c< F, 0c, R, Ks > copy 4c or 5c onto 0c
 
>handle [ : Save code index of [ on "["-stack (deck 5d)
4c: 2d, F 0c, R Ks > copy code index to 0c
    F, Ah Qd > index to hearts
    F, R, 5d, F 0h Ks> move heart index to 5d
    Ac, F, 0c, R Ks > copy Ac onto 0c
 
(check ] : If character at code-index is code is ]
           goto to handle ], else goto              )
5c: 6c, F, 7c, F, > load if
    4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
    F, 9h 3h, F, Ah, Qs > cur char == 93
    >6c, F, 7c, F,< >93 or 0d< Qh > if cur char == 93 6c, else 7c
    >6c or 7c< F, 0c, R, Ks > copy 6c or 7c onto 0c
 
(handle ] : Pop last [ index from "["-stack, store both as decks
            in the heart column, holding their pair's index             )
6c: >Error handling if no matching [
    6d, F, 0c, F, > load error deck and 0c
    5d, Jh > Get size of "["-stack
    >"["-stack size< F, 0s, F Ad, Qs > size equivilant to 0?
    >6d, F, 0c, F< >stack 0?< Qh > If stack 0? then 6d, else 0c
    >6d or 0c< Js > Move to 6d or stay
    >Setting [] pair references in hearts column
    F, 5d, F, 0c, F, 0s, Ks > copy last [ pos onto 0c
    F, Ah, Qd > to hearts
    R > load
    2d, F, 0c, R, Ks F, Ah, Qd > copy ] pos to hearts
    >R, F, index hearts< F, 0h, Ks > move last [ pos+1 onto deck hearts ]
    >>>>
    2d, F, 0c, R, Ks F, Ah, Qd > copy ] pos+1 to hearts
    R > load
    5d, F, 0c, F, 0h Ks > move last [ pos to 0c
    >R< >last [ pos< F, 0h, Ks > copy ] pos+1 to deck [
    Ac, F, 0c, R Ks > copy Ac onto 0c
 
(check < : If character at code-index is <
           goto parse loop control, else goto check >                )
7c: Ac, F, 8c, F, > load if
    4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
    F, 6h 0h, F, Ah, Qs > cur char == 60
    >Ac, F, 8c, F,< >61 or 0d< Qh > if cur char == 61 Ac, else 8c
    >Ac or 8c< F, 0c, R, Ks > copy Ac or 8c onto 0c
 
(check > : If character at code-index is >
           goto parse loop control, else goto comment                )
8c: Ac, F, 9c, F, > load if
    4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
    F, 6h 2h, F, Ah, Qs > cur char == 62
    >Ac, F, 9c, F,< >62 or 0d< Qh > if cur char == 62 Ac, else 9c
    >Ac or 9c< F, 0c, R, Ks > copy Ac or 9c onto 0c
 
(comment: delete current character, --code-index
          --code-size, goto parse loop control.          )
9c: 4d, F, R, > load deletion
    2d, F, 0c, R Ks > copy code index
    >index< F, Ah, Qd > turn index to hearts
    >4d, F, R,< >index h< Ks > delete cur char
    2d, F, 0c, F, 0h, Ks > move code index 0c
    >index< F, As, F, Ac, Qc > index - 1
    F, R, 2d, F, 0h, Ks > move index - 1 to 2d
    3d, F, 0c, F 0h, Ks > move code size 0c
    >index< F, As, F, Ac, Qc > size - 1
    F, R, 3d, F, 0h, Ks > move size - 1 to 3d
    Ac, F, 0c, R Ks > copy Ac onto 0c
 
>Reset: Reset code-index, begin executing
1c 0c: >Error handling if remaining [
       2d, F, 0c, F, 0h Ks > copy code index here
       >code index< F, Ac, F, As, Qc > --code index
       R, F, 2d, F, 0h, Ks >move code index to 2d
       0c, F, 6d, F, > load 0c and error deck
       5d, Jh > Get size of "["-stack
       >"["-stack size< F, 0s, F Ad, Qs > size equivilant to 0?
       >0c, F, 6d, F,< >stack 0?< Qh > If stack 0? then 0c, else 6d
       >0c or 6d< Js > stay or move to 6d
       2d, R, 0h Ks > delete code index
       Ac > -1
       R, 2d, F, 0h, Ks > set code index = -1
       1c 1c F, 0c, R Ks > copy 11c onto 0c
 
>executing---------------------------------------------------------------
 
1c 1c: >If code index = code size, stop
       0c, F, 1c 2c F > load if results
       2d, F, 0c, F 0h, Ks > move code index here
       >code index,< F, As, F, As, Qc > code index + 1
       F, R, 2d, F, 0s, Ks > copy code index + 1 to 2d
       F 3d, F, 0c, R Ks > copy code size to here
       >index F code size< F Ad Qs > code index = code size equivilant
       >0c, F, 1c 2c, F, (index=size)< Qh
       >0c or 1c 2c< F, 0c, R Ks > copy 1c 2c onto here if code index is less than code size
 
1c 2c: 4d, F, 0c, F, 2d, F, 0c, F, R Ks, Ks > copy cur char onto 0c
       F, Ac, Qd > turn cur char to clubs
       >cur char as deck,< F, 0c, R, Ks > copy cur char deck onto 0c
       >cur char happens<
       1c 1c F, 0c, R, Ks > copy 11c onto 0c
 
>if over 255, need to set to 0
4c 3c: ( + 43 )
       0s, F, >load if
       0d, F, 0c, R, Ks > copy cell index to 0c
       >cell index,< F, 0c, F, 0h, Ks > move cell index [data] to 0c
       >cur data< F, As, F, As, Qc > cur-data++
       F, R, 0c, F, 0s, Ks > copy cur data
       >cur data<
       >cur data2< F, 2s 5s 6s, F, Ad, Qs > equivilant to 256?
       >0s, F,< >cur data< F, >256 or #f< Qh >if true, 0, else data
       R, > load move
       0d, F, 0c, R, Ks > copy cell index to 0c
       >R, cell-index,< F, 0h, Ks > move top of R to cell index
 
>replace \/
4c 1c: 4c 1c, F, 4c 1c, R Ks > copy this onto this
       0d, F, 4c 1c, R, Ks > copy cell index to 0c
       >cell index< R, R, Ks > delete cell [index]
       5d, F, > load
       0d, F, 4c 1c, R, Ks > copy cell index to 0c
       >5d, F, cell-index< F, 0h, Ks > move top 5d to cell [index]
       0c, Js
       4c 1c, F, 4c 1c, R Ks > copy this onto this
 
4c 2c: 4c 2c, F, 4c 2c, R Ks > copy this onto this
       5d, R, R, Ks > delete 5d
       5d, F, Ad, Jd > input data onto 5d
       0c, Js > move back to 0c
       4c 2c, F, 4c 2c, R Ks > copy this onto this
 
>>need to handle eofs
4c 4c: ( , 44 )
       4c 2c, F, 0c, F, > load ifs
       5d, Jh> get # args 5d
       >5d< F, 0s, F, Ad, Qs > # args = 0
       >4c 2c, F, 0c, F,< >true or false< Qh > if true, get input, then replace, if false, just replace
       Js > move to 42c or stay here
       >check 5d eof
       0c, F, 4c 1c, F, > load ifs
       5d, Jh, >get 5d size
       >5d size< F, 0s, F, Ah, Qs >5d size equal 0?
       >0c, F, 4c 1c, F,< >5d size or 0d< Qh >if true, 0c otherwise 4c 1c
       >0c or 4c 1c< Js > goto 0c or 4c 1c
 
4c 5c: ( - 45 )
       2s 5s 5s, F, > load if
       0d, F, 0c, R, Ks > copy cell index to 0c
       >cell index,< F, 0c, F, 0h, Ks > move cell index [data] to 0c
       >cur data< F, As, F, Ac, Qc > cur-data--
       F, R, 0c, F, 0s, Ks > copy cur data
       >cur data<
       >cur data2< F, Ac, F, Ah, Qs > equal to -1?
       >2s 5s 5s, F,< >cur data< F, >-1 or #f< Qh >if true, 255, else data
       R, > load move
       0d, F, 0c, R, Ks > copy cell index to 0c
       >R, cell-index,< F, 0h, Ks > move top of R to cell index
 
4c 6c: ( . 46 )
       0d, F, 0c, R, Ks > copy cell index to 0c
       >cell index< F, 0c, F, 0s, Ks > copy cell [index] to 0c
       >cur data< F, Ah, Qd > turn cur-data to heart
       R, 4c 7c, F, 0h, Ks > move cur-data copy to 4c 7c
       4c 7c F, Ac, Jd > print cur-cell
       4c, 7c, R, R, Ks > delete stack
 
6c 0c: ( < 60 )
       >Cell Underflow error handling
       9d, F, 0c, F, > load error deck and 0c
       0d, F, 0c, F, 0s Ks > copy cell-index here
       >cell-index< F, 0s, F Ad, Qs > cell-index equivilant to 0?
       >9d, F, 0c, F,< >cell-index 0?< Qh > If cell-index 0? then 9d, else 0c
       >9d or 0c< Js > stay or move to 9d
       >Move cell index down 1
       0d, F, 0c, F, 0h, Ks > move cell index to 0c
       F, As, F, Ac, Qc > cell index--
       R, 0d, F, 0h, Ks > move top stack onto 0d
 
6c 2c: ( > 62 )
       0d, F, 0c, F, 0h, Ks > move cell index to 0c
       F, As, F, As, Qc > cell index++
       R, 0d, F, 0h, Ks > move top stack onto 0d
       6c 3c, F, 6c 4c, F,> load if
       0d, F, 0c, F, R, Ks > Copy cell index to 0c
       F, 1d, F, 0c, F, R, Ks > Copy max cell index to 0c
       >cell index, F, max cell,< F, Ad, Qs > max cell = cell index?
       >6c 3c, F, 6c 4c, F, max=index< Qh > if max=index -63, else -64
       >-63 or -64< F, 0c, R, Ks > Copy 63 or 64 onto 0c
 
6c 3c: 1d, F, 0c, F, 0h, Ks > move max cell index to 0c
       F, As, F, As, Qc > max cell++
       R, 1d, F 0h, Ks > move new max cell to 1d
       0s, R, > load
       1d, F, 0c, R, Ks > copy max cell to 0c
       >R, max cell< F, 0h, Ks > move 0s from stack to max-cell
 
 
9c 1c: ( [ 91 )
       9c 2c F, 9c 0c F, > load
       0d, F, 0c, R, Ks > get copy of cell index
       >cell index< F, 0c, R, Ks > get value at deck [cell index]
       >value< F, 0s, F, Ad Qs > is value = 0
       >9c 2c F, 9c 0c F, val=0< Qh > if so, 92c, else 90
       F, 0c, R Ks > copy either 92c or 90c onto 0c
 
9c 2c: 2d, F, 0c, F 0h, Ks > move code index to 0c
       >code index< F, Ah Qd > hearted
       >[ key< F, 0c, R, Ks > get value at deck [code index]
       R, 2d, F, 0h, Ks > set code index to resulting number
 
9c 3c: ( ] 93 )
       9c 5c F, 9c 4c F,
       0d, F, 0c, R, Ks > get copy of cell index
       >cell index< F, 0c, R, Ks > get value at deck [cell index]
       >value< F, 0s, F, Ad Qs > is value = 0
       >9c 5c F, 9c 4c F, val=0< Qh > if so, 95c, else 94c
       F, 0c, R Ks > copy either 95c or 94c onto 0c
 
9c 4c: 2d, F, 0c, F 0h, Ks > move code index to 0c
       >code index< F, Ah Qd > hearted
       >[ key< F, 0c, R, Ks > get value at deck [code index]
       R, 2d, F, 0h, Ks > set code index to resulting number
 
>variables & constants
0d: 0s > cell index
1d: As > largest cell tracker. +1 if reach new max
2d: 0s > code index
3d:    > code size
4d:    > bf code
5d:    > "[" stack
 
>Errors
6d: >hanging "]" error
    7d, F, Ac, Jd > print 7d
    4d, F, 6d, F, > load
    2d, F, 6d, F, 0s, Ks > copy code index to here
    >4d, F, 6d, F,< >index< Ks > copy index char to here
    F, R, F, Ac, Jd, F > Print cur char
    >print char
    8d, F, Ac, Jd > print 8d
    2d, F, Ac, Jd > print code index
>"Hanging ""
7d: 7h 2h FR 9h 7h FR Ah Ah 10h FR Ah 10h 3h FR Ah 10h 5h FR Ah Ah 10h FR Ah 10h 3h FR 3h 2h FR 3h 4h FR
>"" at index "
8d: 3h 4h FR 3h 2h FR 9h 7h FR Ah Ah 6h FR 3h 2h FR Ah 10h 5h FR Ah Ah 10h FR Ah 10h 10h FR Ah 10h Ah FR
    Ah 2h 10h FR 3h 2h FR
 
9d: >cell underflow error
    Ad 0d, F, Ac, Jd > print Ad 0d
    2d, F, Ac, Jd > print code index
>"Cell underflow at index "
Ad 0d: 6h 7h FR Ah 10h Ah FR Ah 10h 8h FR Ah 10h 8h FR 3h 2h FR Ah Ah 7h FR Ah Ah 10h FR Ah 10h 10h FR
       Ah 10h Ah FR Ah Ah 4h FR Ah 10h 2h FR Ah 10h 8h FR Ah Ah Ah FR Ah Ah 9h FR 3h 2h FR 9h 7h FR
       Ah Ah 6h FR 3h 2h FR Ah 10h 5h FR Ah Ah 10h FR Ah 10h 10h FR Ah 10h Ah FR Ah 2h 10h FR 3h 2h FR

4.2 Development🔗ℹ

RifL was started in my Sophomore year of college, with the goal of creating an esoteric language that could be run physically. It was partially finished there, and the first build was completed 3 years later. The parser was built in Brag up until 1.02, but was rebuilt 1.2 in plain beautiful racket.

I intend RifL to receive updates in the future, for a few reasons:

First, the functionality of RifL is not complete. I intentionally left some Royal cards incomplete or not implemented at all. This is the first language I have designed, and as such, I know that letting some of the functionality grow out of user needs rather than design ideas is healthy. In a language like RifL that can have only 12 functions, leaving myself some open space is required to do this.

Second, the current debugging systems RifL gives you to step through code is crude and inefficient. In the future I will provide more natural feeling ways to see what RifL code is doing while it is running. Luckily, you can just run RifL code physically for yourself to see what is happening. That is always the best approach for debugging small portions of RifL.

4.3 Aknowledgments🔗ℹ

Keith O’Hara, my computer science professor of my design of programming languages, as well as my thesis advisor, and all around great guy. If you ever get a chance to learn from this man, take that opportunity. He is what so few manage to be: a good programer, an excellent teacher, and a great person. If you see him, tell him I say hi.

Matthew Butt­erick and his great online textbook, beautiful racket, as well as the Beautiful Racket and Brag libraries. If you are interested in building a coding language in Racket, I recommend you start here.

Greg Hendershott, a good online teacher and expert in the weird and strange world of Racket and Racket macros. I have not yet had the pleasure of meeting this Racket wizard in his tower, but if you do, listen carefully.

Corbob, for taking the time to review the documentation, as well as giving suggestions on the debugging functionalities.