match
match is an esoteric programming language created by User:Japi. It follows a functional programming paradigm.
Basic Features
Functions
Every program is made up of functions. They are defined by their name, pattern branches, and expressions to evaluate. Each branch is terminated by a semicolon, and the whole function is terminated by another semicolon.
name: pattern1 -> expr1; pattern2 -> expr2; ... patternN -> exprN;;
For example, here is a function that adds one to the argument.
add_one: number -> number + 1;;
Expressions and Patterns
Parentheses can be used in both patterns and expressions. There are only a few literals:
'a' | character literal "Hi" | string literal 1.3 | number literal false | boolean literal nil | nil literal, marks the end of a cons list
String literals can only be used in expressions, everything else can be used in both patterns and expressions. There are some basic binary operators:
+ | Adds two numbers - | Subtract two numbers * | Multiplies two numbers / | Divides two numbers , | Makes a pair, usually called cons (right-assoc) % | Modulus operator < | Less than operator > | Greater than operator = | Equality check then | Returns the result of the right hand side
In patterns, you can match on literals, deconstruct pairs, and bind results to values. To call a function, you can use the C-style syntax.
print("Hello, world!")
Although, commas will be treated as part of the expression and not separation between arguments because every function takes one argument.
Pairs
Because there is no easy way to curry functions, multiple arguments are usually passed via a cons list, or just a pair. String literals are actually just a cons list of characters. Both of these expressions evaluate to the same thing.
'h', 'i', nil "hi"
This is also the reason why they can't be used in patterns, you'll have to use the character literals directly for matching on strings.
Command line arguments
The main function accepts an argument, that argument is usually thrown away with a wildcard pattern but it represents the command line arguments for the program. They are given via a cons list, where if there were no arguments given it would be nil.
main: args -> println(args);;
Guards
Guards can be added to patterns after a colon. The guard's value must be a boolean, and only one guard can be supplied to a pattern. The filter function is a good example of this, it takes a list and a predicate, and filters the list to a list only containing the values that follow that predicate.
filter: nil, _ -> nil; (x, xs), pred: pred(x) -> x, filter(xs, pred); (x, xs), pred -> filter(xs, pred);;
Includes
You can also include a specific file in your code like this:
include "other_file.match"
It'll import all the definitions of the functions in that file and the includes int that file, and allow you to use it in your code. You can do multiple includes from anywhere in the program, and any include from a specific file will only be included once. So if a file predicates.match looked like this:
even: n -> n % 2 == 0;;
Then a file main.match could look like this:
include "predicates.match" main: _ -> println(even(2));;
Examples
Hello, world!
main: _ -> println("Hello, world!");;
truth-machine
truth: '0', nil -> println(0); '1', nil -> print(1) then truth("1"); _ -> error("Please type a '0' or '1'.");; main: _ -> print("Type a '0' or '1': ") then truth(readln(nil));;
Sum of list
sum: nil -> 0; x, xs -> x + sum(xs);; main: _ -> println(sum(1, 2, 3, 4, nil));;
This should output 10.
External resources
- Official interpreter written in Rust by User:Japi
- Rule 110 implementation by User:Japi