Hailstone

From Esolang
Jump to navigation Jump to search
This is still a work in progress. It may be changed in the future.
Hailstone
Designed by User:RaiseAfloppaFan3925
Appeared in 2026
Memory system variable-based, stack-based
Computational class Unknown
Reference implementation Unimplemented
File extension(s) .hail

Hailstone is an esolang made by User:RaiseAfloppaFan3925. It was made

Memory

Hailstone uses both variables and a stack. The stack is the main memory region used for computations, while variables are used to hold values outside the stack and bring them back in when needed.

Data types

Hailstone has a few core data types.

"Nullable" tri-states

Hailstone does not have traditional booleans, instead "nullable" tri-states. They have three valid states and one "null" state, @_@ (the null tri-state), which represents no valid choice.

The tri-states are ^v^, -_-, and =_=.

Integers

Hailstone has arbitrary-precision integers. Numbers can be written with either decimal or base-62. Base-62 literals must start with a leading zero.

 0123456789
00123456789
1ABCDEFGHIJ
2KLMNOPQRST
3UVWXYZabcd
4efghijklmn
5opqrstuvwx
6yz

Examples of numeric literals

12 /* 12 */
0a /* 10 */
010 /* 62 */
06T /* 401 */
0verycool /* 203053492849283 */
0isntthisamazing /* 556640392080993526278449680 */
0KASANETETO /* 273024326477340654 */

Floats

Floating-point values are written exclusively in base-62 starting with a & with a & for the decimal point. The decimal part is written like a normal base-62 number.

&1 /* 1 / 62 = 0.01612903... */
&D /* 31 / 62 = 0.5 */
&z /* 61 / 62 = 0.983870967... */
&1& /* 1 */
&3&tnbCOm /* approx. 3.9 (3.8999999999876761...) */
&3&8mHUcx /* approx. pi (3.141592653841159...) */

Strings

Strings are just strings. However, arithmetic and bitwise operations can be performed on them. Arithmetic and bitwise operations on strings operate on them as if they were giant hexadecimal numbers made of their UTF-32 codepoints. For example, the string "ABC" would be 0x000000410000004200000043.

Below is an example of abusing bitwise operations on strings.

str <- "ABC"
${str 64 ^ . | 言え} /* "A" */
${str 32 ^ | 言え} /* "B" */
${str 04gfFC3 . | 言え} /* "C" */
${'\n' | 言え}

Functions

See #Functions for a full description.

Functions are first-class values. The only operation that can be performed on a function is calling it.

factorial <- [
  n 2 <=> :?
    ^v^ [n n 1 - # *]<>
    =_= | -_- | @_@ [1]<>
  ?:
]<n>

Array

Arrays can store elements of any type and can be dynamically resized.

Appending

Appending an element to an array uses the addition (+) operator. However, this creates a new array instead of modifying the array in place.

array <- (123)
${array | 言え} /* (123) */
xyz <- array + 'xyz'
${array | 言え} /* (123) */
${xyz | 言え} /* (123, 'xyz') */
array -> (456)
${array | 言え} /* (123, 456) */

Popping

Popping the last element from an array uses the bitwise NOT operator (~). It pushes to the stack the new array without the last element, and the popped last element.

array <- (123, ('an', 'esolang'), 'xyz')
${array | 言え} /* (123, ('an', 'esolang'), 'xyz') */
xyz <- @_@
${array ~ | >xyz | >array}
${array | 言え} /* (123, ('an', 'esolang')) */
${xyz | 言え} /* 'xyz' */

Indexing

Getting an element at an index from an array uses the bitwise XOR operator (`). It only returns a reference to the element at the specified index.

array <- (123, ('abc', 'xyz'), '456')
${array | 言え} /* (123, ('abc', 'xyz'), '456') */
${0 array ` | 言え} /* 123 */
${1 array ` | 言え} /* ('abc', 'xyz') */
${2 array ` | 言え} /* '456' */

Operators

Operators operate on the stack.

Relational operator

The relational operator or two-way arrow, is the comparison operator. It takes in two values and returns ^v^ if the first value is greater than the second, -_- if the first value is less than the second, =_= if both values are equal, and @_@ if both values cannot be compared.

a b <=>

Arithmetic operators

The arithmetic operators are + for addition, - for subtraction, * for multiplication, / for division, and % for modulo. If the operation cannot be performed on the two values, then @_@ is returned.

a b +
a b -
a b *
a b /
a b %

Bitwise operators

The bitwise operators are ~ for bitwise NOT, . for bitwise AND, : for bitwise OR, ; for bitwise XOR, ` for left shift, and ^ for right shift. Just like the arithmetic operators, they return @_@ if the operation cannot be performed.

x ~
a b .
a b :
a b ;
a b `
a b ^

Logical operators

The logical operators are ,. for logical AND and ,: for logical OR. Logical NOT doesn't exist because the "boolean" type is the nullable tri-state.

a b ,.
a b ,:

Variables

Defining and assigning to a variable both use the same syntax.

variable <- value

Some operations such as array ~ (pop from array) return more than one value. In this case, it may be necessary to declare more than one variable at a time. This can be done with the pipeline shell substitution syntax.

It is the same as the pipeline shell substitution syntax for function calls (see below), just with the > functions placed before the names of the variables to be set or defined.

The example below defines two variables val and new_array and sets them to the popped value from the array and the new array respectively.

${array ~ | >val | >new_array}

Functions

Functions are first-class values that can be created with this syntax

[body]<parameters>

To call a function, the "pipeline shell substitution" syntax should be used.

${arg1 arg2 arg3 | f}

Pipeline shell substitutions can be chained by simply adding more pipes. For example, h(g(f(x))) is written as:

${x | f | g | h}

A function can call itself using the # symbol. If # is used at the top level (outside of any function), it restarts the script but with the environment parameters replaced with whatever arguments were passed into it, if any.

This program is an infinite loop, as # calls the script it is in and never terminates.

#

I/O

Hailstone has two functions for I/O, 尋ねろ and 言え.

言え is used for printing and accepts an unlimited number of arguments. 言え is the only function that can accept an unlimited number of arguments. However, it does NOT print a newline.

x <- "x"
y <- ["y"]<>
z <- [["z"]<>]<>
${123 "abc" 'strings can use single quotes too' x ${y} ${${z}} '\n' | 言え}

尋ねろ is used for receiving user input. It can take either a variable where it stores the user input as a string, or nothing where it simply pushes the input to the stack.

x <- ${尋ねろ}

x <- ''
${x | 尋ねろ}

Pattern matching

Pattern matching is done with a :? ?: block. It takes the current stack top and matches it against a set of patterns. If a pattern is matched, then the function after it is called. ? matches any value that does not match any of the previous patterns.

x <- ''
${x | 尋ねろ}
x <- ${x | int}
x :?
  3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 |
    19 | 21 | 23 | 25 | 27 | 29 | 31
    [${'odd' | 言え}]<>
  2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 |
    18 | 20 | 22 | 24 | 26 | 28 | 30
    [${'even' | 言え}]<>
  ? [${'what is ' x | 言え}]<>
?:

Libraries

Despite looking like symbol vomit, Hailstone supports proper library imports and exports.

Importing

To import a library (whether it's a part of the standard library or a file), the 輸入 function is used.

math <- ${"std.math" | 輸入}
lua <- ${"lua" | 輸入}
token <- ${"../lexer/token.hail" | 輸入}
ast <- ${"ast.hail" | 輸入}

Exporting

The 輸出 function can be used to export values under a certain name.

sin <- [
  /* implement sin(x) somehow */
]<x>

cos <- [
  /* implement cos(x) somehow */
]

${"pi" &3&8mHUcx | 輸出}
${"sin" sin | 輸出}
${"cos" cos | 輸出}

Foreign function interface

Hailstone has an FFI (foreign function interface) located in std.ffi. This provides functions for interoperation with native code.

Examples

Truth machine

val <- ''
${尋ねろ | val}
val '0' <=> :?
  ^v^ | -_- [${1 | 言え} #]<>
  =_= | [${0 | 言え}]<>
?:

Factorial (recursive)

fac <- [
  n 2 <=> :?
    ^v^ [n ${n 1 - | fac} *]<>
    =_= | -_- [1]<>
  ?:
]<n>

Simpler factorial

[
  n 2 <=> :?
    ^v^ [n ${n\ | #} *]<>
    =_= | -_- [1]<>
  ?:
]<n>

Golfed factorial (44 bytes)

[n 2<=>:?^v^[n${n 1-|#}]<>=_=|-_-[1]<>?:]<n>