Miled is an esoteric language.
"Hello, world!"
This is a valid Miled program, and it outputs Hello, world
, as one would expect.
-
Put a space (or any whitespace symbol) between any two lexemes. This is because a word with no spaces will be considered as an identifier, even starting with numbers. So for example,
+ 1 1
is correct, but+1 1
is not. But if a word starts with a quote"
, it will be considered as the start of a string, which ends at the next quote. -
Prefix notation. The No. 1 rule to remember everywhere. So it's not
2 > 1
, it's> 2 1
. -
Functions automatically consumes input and executes. Imagine calling a function using the normal
f(x, y, ...)
notation, but remove all commas and parentheses; that's how you call functions in Miled. -
Since identifiers must be separated by whitespaces, Miled accepts any character in an identifier, unless a quote appears as the first character. In this case Miled would assume it's the beginning of a string.
Functions, or more commonly appeared in the source code as callers, are basically automatically curried
functions. Take +
as an example. +
takes 2 parameters and return the sum of them. Remember that this language
uses prefix notation:
+ 1 2
outputs 3
. To show that it's curried we assign a partially-completed ("unfulfilled") caller to a variable:
:= x + 1 ;!
The ;!
at the end means "termination" (explained later), which basically stops +
from consuming further inputs.
This time x
has yet another parameter to fill in, so we call x
directly:
:= x + 1 ;! x 2
outputs 3
.
There are 2 methods to force a caller to terminate and return. The first one, presented above, returns the unfulfilled
caller directly, and waits for further input. The second one, often called enclosing, fills the remaining input slots
with None
, and executes it. If the arity of this caller is indeterminate, enclosing it will execute it immediately
with current arguments.
After a caller is executed, it doesn't wait for any more input, and will become an immediate value. For example
:= x + 1 ;! := y x 2 y
still outputs 3
. (Note: :=
consumes only 2 parameters, so after := y x 2
, the :=
caller is already fulfilled,
and the remaining y
is returned.)
An example with indeterminate-arity callers:
:= x n+ ;! := x ;! x 1 ;! x 2 ;
n+
is the indeterminate-arity version of +
, which means it will consume all inputs until it's enclosed by ;
(at
the end of this program). Also notice the first ;!
in := x ;! x 1 ;!
, this is required, as if it's not present,
the interpreter will first try to evaluate the caller x
first.
For a complete list of builtin callers, refer to [this document](./The Built-In Table.md).
NOTICE THAT, this language is somewhat stack-based, so once your parameter is pushed into the stack it cannot be changed. Take this example:
:= x [ 1 2 3 ; push x pop x x
This code defines a list x = [1, 2, 3]
, then push the popped value. But actually it returns [1, 2, 3, 3]
! That's
because once x = [1, 2, 3]
is in the stack of push
, it is not changed since then. The right way is
:= x [ 1 2 3 ; pushto pop x x x
First pop, then push to stack. This returns [1, 2, 3]
.
if: ... :fi
if:: ... else ... :fi
while: ... :ihw
Nothing much to explain. Just be careful that else
also closes all open branches (if:
's, while:
's) after the
nearest if::
, and :ihw
closes all open branches after the nearest while:
. For example:
while: ... if: ... :ihw
is valid code.
Notice that open branches are automatically closed at EOF.
def <name of caller> <list of param> <: ... :>
Still, nothing much to explain. Example:
def gcd cS "xy" <:
if:: div min x y max x y min x y
else gcd min x y % max x y min x y :fi
:>
def lgcd cS "x" <:
while: >= len x 2 pushto gcd pop x pop x x :ihw
@ x 0
:>
Notice that the second argument must be a list of strings.
You use fn
for inline anonymous callers:
:= x [ 1 2 3 ; map fn cS "x" <: + x 1 :> x"
Notice that open <:
's are automatically closed at EOF.
Sometimes it's just convenient to set up a scope. def
or fn
callers set up a scope for defined callers, but if
and while
do not set up a scope. Similar to many languages, Miled use {
and }
to mark code blocks:
:= x 3 { := x 4 } x
This outputs 3, because :=
defines a variable in the current scope.
:= x 3 { <- x 4 } x
This outputs 3, because <-
will check for the nearest scope with x
defined and set the value. (If no scopes with x
defined are found, <-
will work in the current scope.)