Functional programming made simple
Minimal instead of feature rich Programmable json
Easy to understand, for both humans & computers Suitable for data & calculations, but not interactive programs with side effects

Functional & imperative & generic programming

Manglang

Manglang is an experimental programming language that is simple and minimal. It is suitable for describing data and calculations, but not interactive programs with side effects. Manglang code can either be evaluated using its stand-alone interpreter or be embedded as a scripting language within C++.

Code Evaluation

Manglang is a functional and interpreted language. It takes source code written in Manglang and evaluates it. Consider the following input program:

{
  rectangles = [
    {width = 3 height = 1}
    {width = 6 height = 2}
    {width = 3 height = 6}
    {width = 8 height = 4}
  ]
  get_area = in {width height}
    out mul!(width height)
  areas = map!(get_area rectangles)
  total_area = sum!areas
  num_rectangles = count!rectangles
  average_area = div!(total_area num_rectangles)
}

When we evaluate the input above we get the output below:

{
  rectangles = [
    {width = 3 height = 1}
    {width = 6 height = 2}
    {width = 3 height = 6}
    {width = 8 height = 4}
  ]
  get_area = in {width height}
    out mul!(width height)
  areas = [3 12 18 32]
  total_area = 65
  num_rectangles = 4
  average_area = 16.25
}

Note that both the input and output is written in the same language! A Manglang program does not have any side effects. It just results in a value. The Manglang format can be used to both write programs and to express pure data.

For more code examples continue reading below, or look inside the standard library. There is also documentation for all functions.

Building Blocks

Manglang consists of the following basic building blocks:

Atoms like numbers and characters and booleans.
Containers holding data like dictionaries, tuples , stacks, strings and tables.
Control flow like if, is, while, for and dynamic.
Function definitions and function applications which transform data.
Type Annotation

Below you will find descriptions and examples of each of these language constructs.

1. Atoms

Manglang has three kinds of atomic or primitive data: numbers, characters and booleans.

1.a. Numbers

Manglang has a single number type which is a 64 bit float:

12.34

1.b. Characters

A single ascii character is written as:

'a'

1.c. Booleans

A boolean is either:

yes
or
no

In Manglang we see booleans as answers to questions and therefore write them as yes and no instead of true and false. This is closer to natural language and also shorter.

2. Containers

Manglang has five different kinds of containers which can store other data inside them: dictionaries, tuples, stacks, strings, tables.

2.a. Dictionaries

Dictionaries are used to associate names / symbols with expressions:

{pi=3.14 first_letter='A'}

Manglang doesn't care about extra whitespace so the program above can also be written as:

{
  pi = 3.14
  first_letter = 'A'
}

Dictionaries can be nested:

{
  rectangle = {width = 4 height = 5}
  circle = {radius = 5}
}

Reference to Current Dictionary

A name defined in a dictionary can be referenced after it is defined:

{
  a = 1
  b = a
}

The input above is evaluated to the output below:

{
  a = 1
  b = 1
}

Reference to Outer Dictionaries

Dictionaries can be nested. You can also refer to a name in an outer dictionary:

{
  a = 1
  b = {c = 2 d = a}
}

The input above is evaluated to the output below:

{
  a = 1
  b = {c = 2 d = 1}
}

When refering to a name the current dictionary is first checked and then the next outer dictionary and so on.

Reference to Inner Dictionary

You can refer to names in an inner dictionary like this:

{
  a = {b=2 c=3}
  d = b@a
}

The input above is evaluated to the output below:

{
  a = {b=2 c=3}
  d = 2
}

The syntax name@dictionary is used to get the value corresponding to the name/key inside the dictionary. This syntax is reversed compared to most languages that instead write this as dictionary.name. However, having it like this simplifies the syntax of Manglang and makes it easier to parse. It also makes both function application and dictionary lookup follow the same order and pattern.

Dictionaries everywhere

In Manglang dictionaries are the only way to associate names / symbols with expressions. So Manglang uses dictionaries to represent both:

In the next sections we will look at the remaining three containers in Manglang: We will see that each of them can be seen as syntactic sugar sprinkled on dictionaries.

2.b. Tuples

Tuples of values are written as:

(3 17.5 yes 'A')

We use tuples to group different atomics as an ordered collection. The elements of the tuple can have different types, just as the elements of a dictionary can have different types. To see the similarity consider this example:

{
  tuple = (3 17.5 yes 'A')
  dictionary = {item0=3 item1=17.5 item2=yes item3='A'}
}
These are two different ways of storing the same data. Tuples in Manglang can be seen as syntactic sugar sprinkled on dictionaries so that we can use the first more concise notation instead of the second more verbose notation. Conceptually we can think of a tuple as a dictionary but instead of accessing an item in it using name@dictionary we access it with and index like tuple!index. A common use case for tuples is to send multiple inputs of different types to a function.

2.c. Stacks

Stacks of values are written as:

[3 6 4]
There are two differences between tuples and stacks:

If we have a stack we can get the stack with all elements except the first via drop!stack. The function put is used to construct a new stack by putting a new item on top of the stack:

put!(7 [4 5 2])
The input above is evaluated to the output below:
[7 4 5 2]

Here is another example program with some stack operations:

{
  a = [3 6 4]
  b = take!a
  c = drop!a
  d = put!(b c) 
}

The input above is evaluated to the output below:

{
  a = [3 6 4]
  b = 3
  c = [6 4]
  d = [3 6 4]
}
In summary, we interact with stacks by accessing its members using take and drop and via the function put. The standard library of Manglang provides more functions that works on stacks but they are all built on top of this basic interface.

2.d. Strings

Strings are written as:

"Manglang"

They can be seen as stacks of characters. Example of a program using functions on strings:

{
  a = "Manglang"
  b = take!a
  c = drop!a
  d = reverse!a
  e = put!('E' a)
}
The input above is evaluated to the output below:
{
  a = "Manglang"
  b = 'M'
  c = "anglang"
  d = "gnalgnaM"
  e = "EManglang"
}

2.e. Tables

What we call Tables in Manglang are sometimes referred to as associative arrays in other languages. A table holds pairs of elements: keys and values. We use the syntax:

<(key1 value1) (key2 value2)>
Tables are used for situations where you want to quickly get or put the value in a container based on a dynamic key. We do this using the built-infunctions get!(key table default_value) and put!((key value) table). The following example takes a stack of numbers and computes a table, where each key is a number and the corresponding value counts how many times the number occurs in the stack:
{
  stack = [1 2 1 1 3 4 2]
  counts = <>
  for item in stack
    count = inc!get!(item counts 0)
    counts = put!((item count) counts)
  end
}
The input above is evaluated to the output below:
{
  stack = []
  counts = <(1 3) (2 2) (4 1)>
  count = 2
}
Tables are perhaps the most complicated and least used container in Manglang. But they are handy in some cases. Tables are somewhat similar to dictionaries, but also different:

2.f. Container Summary

-----------+---------------+---------+-------------------------------------------
Container  | Item Type     | Size    | Mutability
-----------+---------------+---------+-------------------------------------------
Dictionary | Heterogeneous | Static  | Mutable during constrution, then immutable
Tuple      | Heterogeneous | Static  | Immutable
Stack      | Homogeneous   | Dynamic | Immutable
String     | Homogeneous   | Dynamic | Immutable
Table      | Homogeneous   | Dynamic | Mutable  
-----------+---------------+---------+-------------------------------------------

Dictionaries and tuples are both heterogeneous and static containers. They are used when we know exactly how many items we want to store in the container. We use dictionaries if we want to refer to each item by name. We use tuples if we want to refer to each item by position. By heterogeneous we mean that the items in a container can have different type.

Stacks, strings and tables are all homogeneous and dynamic containers. By homogeneous we mean that each item in a container has the same type. By dynamic we mean that they are suitable for adding and removing items as the program is evaluated. Stacks and strings are immutable, which means that if we add or remove items we get a new copy of the original container with the updated change, whereas the original container is not modified. Tables on the other hand are mutable, so putting new items in a table actually modifies the original container.

2.g. Generic Programming

Stacks, strings, tables as well as numbers and booleans share some basic operations. The following operations can be used to iterate through these dynamic containers:

Stacks, strings, tables, numbers, booleans also share the following operations for creating new containers:

The functions above form the generic interface for containers in Manglang. On top of that three kinds of syntactic sugar is provided that can be used when rebinding names inside a dictionary:

Since Manglang also defines the generic container operations for numbers we can do things like:

{
  n = 3
  container = []
  total = 0
  for _ in n
    container += n
    total += n
  end
}
which is evaluated to:
{
  n = 3
  container = [1 2 3]
  total = 6
}

In the same spirit Manglang also defines the generic container operations for booleans, which means we can use the for loop similar to an if-statement without an else part. Then the body is run once if the boolean is yes and zero times if the boolean is no.

By relying on the generic container interface we can write generic functions that work similarly on both stacks, strings and tables. For some examples of this you can take a look at the standard library documentation, or look inside the standard library implementation.

4. Control Flow

4.a. If

The expression if a then b else c is evaluated to b or c depending on if the answer to the question a is yes or no.

Consider this example:

{
  a = [0 1]
  b = if a then
      take!a
    else
      2
  c = if b then "hello" else "world"
}

This program is evaluated to:

{
  a = [0 1]
  b = 0
  c = "world"
}
An if-expression can look at more than two alternatives. In many languages this is achieved by adding another if after the else as "else if". In Manglang the "else if" can be skipped. Instead we just list all alternatives:
{
  opening = '{'
  closing = if
    equal?(opening '(') then ')'
    equal?(opening '{') then '}'
    equal?(opening '[') then ']'
    equal?(opening '<') then '>'
    else '.'
}
This goes through each alternative until it finds one where the answer is yes. The input above is evaluated to the output below:
{
  opening = '{'
  closing = '}'
}
So an if-expression consists of one or more alternatives and then a mandatory fall-back else.

4.b. Is

The is operator is used to check for equality among many alternatives. It is similar to switch-case or pattern matching in other languages. This provides syntactic sugar instead of a more verbose combination of the if operator and the equal function. Consider this example where we use the is operator to find the corresponding characters:

{
  opening = '{'
  closing = is opening
    '(' then ')'
    '[' then ']'
    '{' then '}'
    '<' then '>'
    else  '.'
}

4.c. While

In Manglang you can loop while constructing a dictionary:

{
  x = 10
  tot = 0
  while x
    tot = add!(tot x)
    x = dec!x
  end
}
The input above is evaluated to the output below:
{
  x = 0
  tot = 55
}

The loop decrements x until it is zero and then finishes. Definitions in a dictionary can only be updated / mutated while the dictionary is constructed. Once it has been constructed it is immutable and cannot be updated.

4.d. For

You can use a for-each-loop to visit each item in a container:

{
  tot = 0
  numbers = [1 2 3]
  for number in numbers
    tot = add!(tot number)
  end
}
This is syntactic sugar for the equivalent while loop:
{
  tot = 0
  numbers = [1 2 3]
  while numbers
    number = take!number
    tot = add!(tot number)
    numbers = drop!number
  end
}
Both versions above evaluate to the output below:
{
  tot=6
  numbers=[]
  number=3
}

There are two things to note about for-loops in Manglang. The first thing is that in the expression for item in name both item and name are names. This means that a container needs to first be given a name before it can be used in a for-loop. The container CANNOT be inlined directly like for item in [1 2 3]. Another thing to note is that the for loop rebinds these names for each iteration of the loop and leave them in their final state after the loop. So in this sense a for-loop consumes the name of the container. If you want to refer to the full container also after the loop then you need to assign a different name to it before entering the for-loop.

4.d. Dynamic

Manglang is statically typed but provides an escape hatch. The dynamic-operator can be used to skip static type checking for the expression that follows it like: dynamic expression. The static type checker considers the type of this to be the top-type \ any-type. But run-time dynamic type-checks are still happening. The dynamic-operator is useful in some rare situations:

Manglang considers the dynamic-operator as an escape hatch that should almost never be used.

5. Functions

5.a. Function Application

We have already seen some examples of calling / applying functions in Manglang. A function is called using ! like function_name!input. We see function application as a command and hence use the symbol ! after the verb that names the functions. Functions take a single value as input. However, this single value can be a stack or tuple or dictionary, that has multiple values inside.

{
  stack = [4 2 1]
  sum0 = sum!stack
  sum1 = sum![4 2 1]
  stack2 = put!(3 stack)
}

This program is evaluated to:

{
  stack = [4 2 1]
  sum0 = 7
  sum1 = 7
  stack2 = [3 4 2 1]
}

Manglang does not have any special operators for arithmetics, boolean, stack operations etc. Instead functions are used for all computations. Function calls can be nested like this:

mul!(add!(1 2) sub!(7 2))

This program is evaluated to (1+2)*(7-2) = 3*5 = 15. Function calls are right associative. Manglang does not support currying.

Applying Predicates

Manglang encourages using ? instead of ! for applying functions that return a boolean value, a.k.a. predicates. Applying such a function is like asking a question. As an example consider the following functions from the standard library that operate on ascii characters:
{
  is_upper = in c out less_or_equal?[65 number!c 90]
  is_lower = in c out less_or_equal?[97 number!c 122]
  to_upper = in c out
      if is_lower?c then
          character!sub!(number!c 32)
      else
          c
  to_lower = in c out
      if is_upper?c then
          character!add!(number!c 32)
      else
          c
}

5.b. Function Definition

Functions are defined using they keywords in and out like this:

{
  square = in x out mul!(x x)
  result = square!3
}

A function definition is on the form in x out expression where x is the name of the input and expression is the output. Functions are first class values and can be given a name by putting them inside a dictionary.

Function definitions and computations can be broken up into smaller parts by using dictionaries:

{
  square = in x out mul!(x x)
  square_norm = in vec3 out result@{
    x = vec3!0
    y = vec3!1
    z = vec3!2
    result = add!(square!x square!y square!z)
  }
  vector = (3 4 5)
  result = square_norm!vector
}
We can implement functions that loops/iterates either by having explicit loops or by using recursive functions:

{
  count_imperative = in stack out result@{
      result = 0
      for item in stack
        result = inc!result
      end  
    }
  count_recursive = in stack out
    if stack then
      dynamic inc!count_recursive!drop!stack
    else
      0
  a = count_imperative![3 7 8]
  b = count_recursive![3 7 8]
  c = count_imperative!"apple"
  d = count_recursive!"apple"
}

This program is evaluated to:

{
  count_imperative = in stack out result@{
      result = 0
      for item in stack
        result = inc!result
      end  
    }
  count_recursive = in stack out
    if stack then
      dynamic inc!count_recursive!drop!stack
    else
      0
  a = 3
  b = 3
  c = 5
  d = 5
}
Manglang encourages for and while loops instead of recursive functions for most use-cases. This is similar to most imperative languages but unlike many functional languages. There are three reasons why Manglang encourages loops instead of recursion:
  1. Loops are subjectively easier to follow for most people.
  2. Loops are easier to implement efficiently for me as the language implementor.
  3. Loops are easier to type check for me as a the language implementor.
Recursive functions are still allowed, since they can be handy in some particular situations. When using recursive functions in Manglang you currently need to use the dynamic operator to tell the static type checker to not check the types for it.

5.c. Function of Tuple Definition

Manglang provides syntactic sugar for defining functions that take multiple input, in the form of a tuple. Here are some examples of equivalent ways of defining and calling functions:

{
  area1 = in rectangle out mul!(rectangle!0 rectangle!1)
  area2 = in (width height) out mul!(width height)
  rectangle = (5 4)
  a = area1!rectangle,
  b = area2!rectangle,
  c = area1!(5 4)
  d = area2!(5 4)
}

The functions area1 and area2 are equivalent. They expect the same input and return the same result. area2 just uses syntactic sugar to make its implementation more concise, by unpacking the elements of the input tuple.

5.d. Function of Dictionary Definition

Manglang provides syntactic sugar for defining functions that take multiple input, in the form of a dictionary with named entries. Here are some examples of equivalent ways of defining and calling functions:

{
  area1 = in rectangle out mul!(width@rectangle height@rectangle)
  area2 = in {width height} out mul!(width height)
  rectangle = {width = 5 height = 4}
  a = area1!rectangle
  b = area2!rectangle
  c = area1!{width = 5 height = 4}
  d = area2!{width = 5 height = 4}
}

The functions area1 and area2 are equivalent. They expect the same input and return the same result. area2 just uses syntactic sugar to make it its implementation more concise, by unpacking the elements of the input dictionary.

6. Type Annotation

Manglang code is evaluated in two separate steps:
  1. Evaluation of types. Quick early verification of the program.
  2. Evaluation of values. Slower evaluation of the whole program.

The second step is the main step which computes the actual result of the program, i.e. the output value. This is what we have focused on so far. This computation might take a long time for some programs. If you are unlucky the program might encounter an error towards the end of the computation after the programming has been running for a while. We want to have a fast feedback loop while programming and discover errors as early as possible. This the motivation for having another pre-step that quickly checks that the program appears to be correct, before we start running it.

The first step does a quick static type checking of the program. It checks if the program seem to make sense. Manglang has a simple type system which supports both type inference and gradual typing. This means that static type checking is happening even when there is no explicit annotation of types in a program. But explicit type annotation can also be added to specify the intention of the program in greater detail.

6.a. Annotating Types for Expressions

You can specify the type of any expression like type:expression. Note that the type and the expression come in the reverse order compared to some other common programming languages. As usual in Manglang white space is optional around :. Let's look at an example:
{
  width = Number:320
  height = Number:240
}

6.b. Annotating Types for Functions

We can also annotate the types for the input and output of functions similarly. Here are some example functions from the standard library:

{
  inc = in Number:x
    out Number:add!(x 1)

  min = in (Number:left Number:right)
    out Number:if less?(left right) then left else right

  min_item = in Numbers:container
    out Number:fold!(min container inf)
}

6.c. Defining Types

Manglang defines the following types in its standard library: Any, Boolean, Number, Numbers, Character, String, Stack, Table, Function. By convention we capitalize the name of types. Inside the standard library this is implemented like:
{
  ...
  Any = dynamic 0
  Number = 0
  Boolean = no
  Character = 'a'
  Stack = []
  String = ""
  Table = <>
  Numbers = [Number]
  Function = in x out x
  ...
}
So a named type is just a named example value for that type. We can name and use our own types similarly:
{
  Age = Number
  Person = {name = String age = Age}
  Persons = [Person]

  anders = Person : {name = "Anders" age = 9}
  ada = Person : {name = "Ada" age = 11}
  persons = Persons : [anders ada]
}

6.d. Checking Types

The static type checker compares pairs of types to see that they compatible. The following hierarchical rules define type compatibility: The types in Manglang form a tree, where a type is compatible with all its descendants and all its ancestors. Type compatibility is a symmetric relation, so if a:b are compatible then b:a are compatible. However, compatibility is not transitive, which means that if a:b are compatible and a:c are compatible, it does NOT mean that b:c are compatible.

More Code Examples

For more code examples look inside the standard library.

Function Documentation

Description of all functions that come with Manglang.

Setup

Manglang is implemented in C++ and does not depend on any external libraries. You can build it in different ways.

Setup via CMake and Make

You can build Manglang from a terminal on a system that has a C++ compiler and Cmake and make. First go to the directory where you want to install manglang and then follow these steps:
  1. git clone git@github.com:mabur/mang_lang.git
  2. mkdir mang_lang/src/build
  3. cd mang_lang/src/build
  4. cmake -DCMAKE_BUILD_TYPE=Release ..
  5. make
This should produce two programs:
  1. The Manglang unit tests which you can try by running ./tests
  2. The Manglang interpreter which you use to run a program written in manglang. You can try running the programs found in the examples directory: ./manglang ../../examples/hello_world.txt

Setup via CLion

You can also build Manglang using CLion:
  1. git clone git@github.com:mabur/mang_lang.git
  2. Open mang_lang/src/CMakeLists.txt in CLion and build.

Setup via Visual Studio and CMake

  1. git clone git@github.com:mabur/mang_lang.git
  2. Open mang_lang/src/CMakeLists.txt in CMake and generate a Visual Studio project.
  3. Open the Visual Studio project and build it.

Setup via Visual Studio

  1. git clone git@github.com:mabur/mang_lang.git
  2. Create a new Visual Studio project and add the header and source files in mang_lang/src/ to it and.
  3. Build the Visual Studio project.

Embed Manglang

Manglang can also be embedded in another C++ program by including src/mang_lang.h and using the function std::string evaluate(std::string code);