MBOL is a small functional language I have thought of for a long time. The idea is to make a language that is mostly based on symbols - an operator language. The idea furthermore is to make it embedded and to make it so other languages can be embedded in it.

I had an assignment at work where we needed a small parser. We found Sprache for C# - a tiny parser combinator that is quite fun to play around with. Perfect for finally building MBOL.

You can read some of the documentation on this page. Or you can play around with the interpreter. MBOL is embedded in terminus by using `` - the result is just a string.

Mbol - Documentation

Let bindings

MBOL is purely functional. Meaning everything should be an expression. However we have let-bindings - these are like "let ... in " in Haskell. You separate each with a ;. So for example you can have a piece of code like:

let a = 2,3;
let b = 4,5;
a,b

Let bindings can be used as tuple deconstructors:

let a = 2;
let b = 3;
let c = a,b;
let d,e = c;
{ 'c':\c , 'd':\d , 'e':\e }

Block expressions

We can create a block of code. We use the keyword block for this. The outer most code is of course a block itself. So we have nested blocks with normal scope ruling:

let a = block
let a = "something"; // will overshadow a
let b = 2;
a,b
;
a

Blocks can be placed right hand of a let binding, or in parentheses any place you can place an expression. For example:

Records

Records are defined using the keyword "record". They can be nested:

let a = record
a : "not here"
, b : (record
a : "here"
, b : "not here"
)
;
a.b.a

As with other structures: nesting has to be done using parentheses.

let a = 2 + (block
let a = 3;
let b = 4;
a * b
);
a

Match expressions

We can do pattern matching with tuple deconstructors:

let a = 1,(2,3),4;
match a with
| 2,(a,b),4 -> "No, not this one"
| 1,(a,b),4 -> block
let c = a + b;
{ yes, this one: \a \b \c }

We can extract elements from lists on match:

let a = [1,2,3,4];
match a,1 with
| 0,1 -> "no, not this one"
| x::y::rest,1 -> {
x:\x
, y:\y
, rest:\rest
}

Note that when trying to extract more elements than a list contains, the case is skipped.

Conditional expressions

Conditional expressions are on the form "if test then expr1 else expr2". Since functional, we need the else-clause for it to be an expression. So this can't be omitted. As an example we have something like:

let a = 200;
let b = 300;
let c =
if a + b < 600 && true
then "yes, we are here"
else "no, not this one"
;
c

if-statements are lazily evaulated meaning that if branch isn't reached, it isn't evaluated. For example in something like "if true then expr1 else expr2" expr2 isn't evaluated at all. We can write "else if" which is essentially just chaining "if ... else ..." expressions:

let a,b = 200,300;
if a > 200 then "not here"
else if b < 300 then "not here"
else if a + b == 500 then "yes, here"
else "not here"

Lambdas

Not yet.

Operators

We have the following operators (binds tighter the lower we get):

&& and || - normal logical operators.

<, <=, >, >= and == - normal comparison operators. More than one is not allowed, eg. we can't have a < b < c.

+,- - normal arithmetic operators. + is overloaded for strings. The rest can only be used with floats or ints.

*, / - normal arithmetic operators. Can be used with floats or ints.

|> - function application. This goes in left direction, eg. 2 |> 3 |> plus. For now only build in functions.

Unary ! and - - works in the expected way.

Literals

MBOL contains the usual literals:

ints, eg 10

floats, eg 10.3

strings, which can be concatenated with +

embeddings, acts like formattable strings in c#. Use {} as open and close, and use \ to fetch variables eg. { 'a' : \a }. Newlines are preserved. The result is just treated as a string.

lists, construct them using [] for open/close. Can contain other literals or expressions, eg. a list of tuples [(1,2),(3,4)]. Note that parentheses are needed since else it would be a list of ints.