# User-defined functions and program control flow ## Writing programs with more than 1 line ### `Operator ;` To effectively write programs that have more than one line, a programmer needs way to specify a sequence of commands that execute one after another. In `scarpet` this can be achieved with `;`. Its an operator, and by separating statements with semicolons. And since whitespaces and `$` (commandline visible newline separator) sign are all treats as whitespaces, how you layout your code doesn't matter, as long as it is readable to everyone involved.
expr;
expr;
expr;
expr
Notice that the last expression is not followed by a semicolon. Since instruction separation is functional in `scarpet`, and not barely an instruction delimiter, terminating the code with a dangling operator wouldn't be valid. Having said that, since many programming languages don't care about the number of op terminators programmers use, carpet preprocessor will remove all unnecessary semicolons from scripts when compiled. In general `expr; expr; expr; expr` is equivalent to `(((expr ; expr) ; expr) ; expr)`. Result of the evaluated expression is the same as the result of the second expression, but first expression is also evaluated for side-effects
expr1 ; expr2 => expr2  // with expr1 as a side-effect
## Global variables All defined functions are compiled, stored persistently, and available globally - accessible to all other scripts. Functions can only be undefined via call to `undef('fun')`, which would erase global entry for function `fun`. Since all variables have local scope inside each function, one way to share large objects is via global variables Any variable that is used with a name that starts with `'global_'` will be stored and accessible globally, not, inside current scope. It will also persist across scripts, so if a procedure needs to use its own construct, it needs to define it, or initialize it explicitly, or undefine it via `undef`
a() -> global_list+=1; global_list = l(1,2,3); a(); a(); global_list  // => [1,2,3,1,1]
### `Operator ->` `->` operator has two uses - as a function definition operator and key-value initializer for maps. To organize code better than a flat sequence of operations, one can define functions. Definition is correct if has the following form
fun(args, ...) -> expr
Where `fun(args, ...)` is a function signature indicating function name, number of arguments, and their names, and expr is an expression (can be complex) that is evaluated when `fun` is called. Names in the signature don't need to be used anywhere else, other occurrences of these names will be masked in this function scope. Function call creates new scope for variables inside `expr`, so all non-global variables are not visible from the caller scope. All parameters are passed by value to the new scope, including lists and other containers, however their copy will be shallow. The function returns itself as a first class object, which means it can be used to call it later with the `call` function Using `_` as the function name creates anonymous function, so each time `_` function is defined, it will be given a unique name, which you can pass somewhere else to get this function `call`ed. Anonymous functions can only be called by their value and `call` method.
a(lst) -> lst+=1; list = l(1,2,3); a(list); a(list); list  // => [1,2,3]
In case the inner function wants to operate and modify larger objects, lists from the outer scope, but not global, it needs to use `outer` function in function signature. in map construction context (directly in `m()` or `{}`), the `->` operator has a different function by converting its arguments to a tuple which is used by map constructor as a key-value pair:
{ 'foo' -> 'bar' } => {l('foo', 'bar')}
This means that it is not possible to define literally a set of inline function, however a set of functions can still be created by adding elements to an empty set, and building it this way. That's a tradeoff for having a cool map initializer. ### `outer(arg)` `outer` function can only be used in the function signature, and it will cause an error everywhere else. It saves the value of that variable from the outer scope and allows its use in the inner scope. This is a similar behaviour to using outer variables in lambda function definitions from Java, except here you have to specify which variables you want to use, and borrow This mechanism can be used to use static mutable objects without the need of using `global_...` variables
list = l(1,2,3); a(outer(list)) -> list+=1;  a(); a(); list  // => [1,2,3,1,1]
The return value of a function is the value of the last expression. This as the same effect as using outer or global lists, but is more expensive
a(lst) -> lst+=1; list = l(1,2,3); list=a(list); list=a(list); list  // => [1,2,3,1,1]
Ability to combine more statements into one expression, with functions, passing parameters, and global and outer scoping allow to organize even larger scripts ### `Operator ...` Defines a function argument to represent a variable length argument list of whatever arguments are left from the argument call list, also known as a varargs. There can be only one defined vararg argument in a function signature. Technically, it doesn't matter where is it, but it looks best at the butt side of it.
foo(a, b, c) -> ...  # fixed argument function, call foo(1, 2, 3)
foo(a, b, ... c) -> ... # c is now representing the variable argument part
    foo(1, 2)  # a:1, b:2, c:[]
    foo(1, 2, 3)  # a:1, b:2, c:[3]
    foo(1, 2, 3, 4)  # a:1, b:2, c:[3, 4] 
foo(... x) -> ...  # all arguments for foo are included in the list

    
### `import(module_name, symbols ...)` Imports symbols from other apps and libraries into the current one: global variables or functions, allowing to use them in the current app. This include other symbols imported by these modules. Scarpet supports cicular dependencies, but if symbols are used directly in the module body rather than functions, it may not be able to retrieve them. Returns full list of available symbols that could be imported from this module, which can be used to debug import issues, and list contents of libraries. ### `call(function, args.....)` calls a user defined function with specified arguments. It is equivalent to calling `function(args...)` directly except you can use it with function value, or name instead. This means you can pass functions to other user defined functions as arguments and call them with `call` internally. And since function definitions return the defined function, they can be defined in place as anonymous functions. Little technical note: the use of `_` in expression passed to built in functions is much more efficient due to not creating new call stacks for each invoked function, but anonymous functions is the only mechanism available for programmers with their own lambda arguments
my_map(list, function) -> map(list, call(function, _));
my_map(l(1,2,3), _(x) -> x*x);    // => [1,4,9]
profile_expr(my_map(l(1,2,3), _(x) -> x*x));   // => ~32000
sq(x) -> x*x; profile_expr(my_map(l(1,2,3), 'sq'));   // => ~36000
sq = (_(x) -> x*x); profile_expr(my_map(l(1,2,3), sq));   // => ~36000
profile_expr(map(l(1,2,3), _*_));   // => ~80000
## Control flow ### `return(expr?)` Sometimes its convenient to break the organized control flow, or it is not practical to pass the final result value of a function to the last statement, in this case a return statement can be used If no argument is provided - returns null value.
def() -> (
   expr1;
   expr2;
   return(expr3); // function terminates returning expr3
   expr4;     // skipped
   expr5      // skipped
)
In general its cheaper to leave the last expression as a return value, rather than calling returns everywhere, but it would often lead to a messy code. ### `exit(expr?)` It terminates entire program passing `expr` as the result of the program execution, or null if omitted. ### `try(expr, catch_expr(_)?) ... throw(value?)` `try` function evaluates expression, and continues further unless `throw` function is called anywhere inside `expr`. In that case the `catch_expr` is evaluates with `_` set to the argument `throw` was called with. This mechanic accepts skipping thrown value - it throws null instead, and catch expression - then try returns null as well This mechanism allows to terminate large portion of a convoluted call stack and continue program execution. There is only one level of exceptions currently in carpet, so if the inner function also defines the `try` catchment area, it will received the exception first, but it can technically rethrow the value its getting for the outer scope. Unhandled throw acts like an exit statement. ### `if(cond, expr, cond?, expr?, ..., default?)` If statement is a function that takes a number of conditions that are evaluated one after another and if any of them turns out true, its `expr` gets returned, otherwise, if all conditions fail, the return value is `default` expression, or `null` if default is skipped `if` function is equivalent to `if (cond) expr; else if (cond) expr; else default;` from Java, just in a functional form