Sheep

From Esolang
Jump to navigation Jump to search
Sheep
Paradigm(s) Functional
Designed by Ashli Katt
Appeared in 2023
Computational class Turing Complete
Reference implementation Unimplemented
File extension(s) .sheep

About

Sheep is a functional esolang where the only datatype is lambda functions. It was invented by constantly simplifying and reducing another language idea, however it essentially became lambda calculus with prefix notation.

Overview

A Sheep program is a list of constant definitions written in the form name value;. The name of an identifier is any number of non-whitespace characters except for /, ., and ;.

A value is one of three things:

  • A named constant/variable reference. name.
  • A lambda declaration. \ name value.
  • A lambda call. . lambda value. (lambda is another value here)

All lambdas take exactly one parameter, but you may use currying to simulate multiple.

Small Notes

  • Comments begin with //.
  • Whitespace only matters to separate identifiers when needed, it is otherwise ignored.
  • The constant main will be called with the program input, and its return value is the output.
  • A variable reference will always use the innermost scope. (ie: Variable Shadowing)

IO Format

The main constant will be called with the program's input, ie: . code input is the initial call. The program input and output are both strings that are converted into nested lambdas.

Suppose our program input is abc, we first convert it into a UTF-8 bitstring: 011000010110001001100011. We then place a 1 before each bit, and pad it with infinite zeroes: 1011111010101011101111101010111010111110101011110000...

To continue, it will be helpful to define two functions:

1 \x \y x; // Takes two args, returns the first.
0 \x \y y; // Takes two args, returns the second.

Our format will resemble a LinkedList where passing 1 into it will return its bit, and 0 will return the rest of the bits. (ie: head and tail). We can write a single node using the following template expression: \bool . . bool if1 if0.

Applying the expression to the format, we get the following: \bool . . bool 1 (rest). Where (rest) would be another copy of this expression, but returning 0 instead (see above bitstring).

Suppose we have the bitstring 101 (This is impossible in practice), we can write it like so:

\b ..b 1
\b ..b 0
\b ..b 1
(infinite zeroes)

Note that these aren't separate statements, they're chained together via the first . on each line.

Finally, (infinite zeroes) can be defined as: infiniteZeroes \b ..b 0 infiniteZeroes. (Note: This can be written with a raw expression, it does not internally use a constant, but it improves readability)

So, in total, 101 becomes: \b..b 1 \b..b 0 \b..b 1 infiniteZeroes, or written without any constants: \i..i\1\0 1\i..i\1\0 1\i..i\1\0 1\i..i\1\0 0.\x\b..b\1\0 0.x x\x\b..b\1\0 0.x x;

The opposite process is done to parse an output back into a string.

Examples

SKI Combinators, proving Turing-Completeness

S\x\y\z . . x z . x y;
K\x\y y;
I\x x;

Cat program.

main \x x;

Church numeral encoding.

0c \x x;
++ \n \x . n . x x;