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"
Function Application
Function application is treated as an operator. Furthermore currying is used. We have two operators - described under operators. However let's dive into the straight forward one here. We do application by writing the function followed by arguments given to it. Like setminus "a" 1 2 - here we set the global value "a" to 1 - 2. Currying is that we can partially evaluate a function, eg:
let a,b = 200,300;
let name = "a";
let f1 = setminus name;
let f2 = f1 a;
f2 b
Here we partially apply arguments to set minus. Each time but the last the result is just a new function.
Though what I have read here and there, I'm pretty sure application is left associative. That is we do it like (((setminus name) a) b).
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 right direction, eg. 2 |> 3 |> plus. For now only build in functions.
- Left function application. This is as normal in languages like Haskell, eg plus 1 2
- 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.
You can use parentheses in the usual way.