# Programs

In a *Script Step* you can use the full range of FlowScript statements.

## Variable declarations

Variables are declared using the `let` keyword and re-assigned using the `set` keyword. Because FlowScript is an implicitly typed language, you cannot declare a variable without also assigning it.

```fsharp
let x = 12;  
set x = x + 1;  
// x is now 13 let
```

## Return statement

To return a value from a FlowScript, use the `return` keyword. The Flow Designer checks to make sure that each branch of a FlowScript returns a value.

```fsharp
return x * 16;
```

## Conditional statement

Conditional statements are written using the if/elseif/else keywords.

```fsharp
if quantity > 100 {
    let discountPercent = 10;
    let amount = quantity * price;
    return amount - (amount * (discountPercent/100));
}
else {
    return quantity * price;
}
```

When the body of a conditional clause consists of only one statement, it is possible to omit the curly braces and use the colon (:) sign instead.

```fsharp
if x > 0:
    return "greater than zero";
elseif x < 0:
    return "less than zero";
else:
    return "zero";
```

## Loops

Loops are written using the `for` and `in` keywords. You can loop over table variables, strings (one iteration per character in the string) and numerical ranges.

### **Table example**

```fsharp
let items = [name: 'soda', price: 4.1] & [name: 'pizza', price: 8.9];
let totalPrice = 0;
for item in items {
    set totalPrice = totalPrice + item.price;
}
```

### **String example**

```fsharp
let barcode = 'A123522BA12332';
let number_of_a = 0;
for c in barcode {
    if c = 'A':
        set number_of_a = number_of_a + 1;
}
```

In order to exit a loop prematurely, you can use the `break;` statement. In order to exit the current iteration and jump right into the next one, use the `continue;` statement.

If the body of a loop consists of only one statement, you can omit the curly braces and use the colon (:) sign instead.

```fsharp
for item in items:
    set totalPrice = totalPrice + item.price;
```

NOTE: To support backward compatibility with previous versions of Novacura Flow, the `do` and `done` keywords are also supported in lieu of the opening and closing curly braces.

### Index loops

To loop over a range of indexes, use the `range(start, count)` function.

```fsharp
for i in range(0, 10) {
    // statements
}
```

## Type declarations

It is possible to define types in FlowScript programs. A type defines the structure of a record (or table) variable. Types are defined like this:

```fsharp
type Person = [name, age];
// This creates a type named 'Person' with simple fields 'name' and 'age'.
```

When creating a new record based on a type, use the following syntax:

```fsharp
type Person = [name, age];
let donaldDuck = Person[name: 'Donald Duck', age: 35];
```

Types can have nested structures:

```fsharp
type Car = [model, year, engine: [power, torque]];
// This creates a type named "Car" with two simple fields (model and year) and a complex (record) field containing sub-fields "power" and "torque".
let myCar = Car[model: 'Volkswagen Golf', year: 2016, engine: [power: 170, torque: 184]];
```

Types can also refer to other types:

```fsharp
type Car = [model, year, engine: [power, torque]];
type personWithCar = [name, age, car: Car];
```

Types always define the structure of record variables. However, by adding the multiplier (\*) unary operator, you can convert a type into the corresponding table type:

```fsharp
type Car = [model, year, engine: [power, torque]];
type PersonWithManyCars = [name, age, cars: *Car];
```

The multiplier (\*) unary operator can also be used when initializing a record:

```fsharp
type Point = [x, y];
type DotGraph = [points: *Point];
let mySingleDotGraph = DotGraph[points: *[1, 1]];
```

It is possible to define default values for type fields. If a default value is given, the field does not have to be initialized.

```fsharp
type Customer = [name, email, phone = 'Not specified'];
let myCustomer = Customer[name: 'Acme Industries', email: 'info@acme.com'];
// myCustomer.phone will now be automatically initialized as 'Not specified'
```

It is possible to use *nil* values for type fields which themselves are records. *nil* values are only permitted for such cases; simple or table values cannot be nil.

```fsharp
type Employee = [name, salary, manager: Employee];
let anEmployee = Employee[
                    name: 'Bob',
                    salary: 10000,
                    manager: Employee[name: 'Alice', salary: 20000, manager: nil]
                ];


if not anEmployee.manager.manager = nil:
    error 'Didn't work';
```

### Automatic types

Each record and table variable in a workflow can also be used as a type. This is useful when you need to programmatically create a record that matches the output from a machine step or some other workflow step. Automatic types are prefixed with the dollar sign ($). For record a variable **`myRecord`**, the automatically created type will be named **`$myRecord_type`** For a table variable `myTable`, the automatically created type will be named **`$myTable_rowtype`**.

```fsharp
let newRow1 = $myTable_rowtype[a: 1, b: 2];
let newRow2 = default($myTable_rowtype) with [b: 2];
```

### Function declarations

Functions are declared using the `let` and `function` keywords.

```fsharp
let least = function(a, b) => {
    if a < b:
        return a;
    else:
        return b;
};
```

For a single-parameter function, no parentheses are needed around the argument list. For a single-statement bodied function, the curly braces, as well as the `return` keyword, can be omitted.

```fsharp
let square = function x => x * x;
```

If no parameter type is given for a function parameter, it is assumed to be a simple value. For complex values (records and tables), the syntax is similar to that of type definitions:

```fsharp
type Employee = [name, salary, position];
let employeesWorkingForFree = function(employees: *Employee) => {
    return employees where salary = 0;
};


let distance = function(point1: [x, y], point2: [x, y]) => {
    return sqrt(pow(point2.x - point1.x, 2) + pow(point2.x - point1.y, 2));
};

return distance([x: 3, y: 28], [x: 99, y: 0]);
```

If no return type is declared for a function, Flow tries to infer the return type based on the function body. It is also possible to specify an explicit return type.

```fsharp
type Employee = [name, salary, position];
let employeesWorkingForFree = function(employees: *Employee) : *Employee => {
    return employees where salary = 0;
};
// This function returns a table of Employee records
```

If recursion is required (i.e. a function that calls itself), return types MUST be explicitly specified. If such a function returns a simple value, the return type should be specified using the `simple` keyword.

```fsharp
let recursiveFunction = function(x) : simple => case when x > 10 then 999 else recursiveFunction(x + 1);
```

NOTE: To support backward compatibility with previous versions of Novacura Flow, the `do` and `done` keywords are also supported in lieu of the opening and closing curly braces.

## Errors

If you need to raise an error from a FlowScript, use the `error` keyword.

```fsharp
error "This is the error message";
```

## Parsing Example

The following FlowScript program example will take a table with one string column and parse it into a table with several columns. It will split columns based on a column delimiter and take the right-side value by using a key-value delimiter.

```fsharp
let newTable = 
    [rowName:'id=1,price=10,name=Soda'] & 
    [rowName:'id=2,price=100,name=Burger'] & 
    [rowName:'id=3,price=50,name=Fries'];

let firstDelimiter = ',';
let secondDelimiter = '=';

let parseFunction = function(rowName, columnIndex, subColumnIndex) =>
    rowName.Split(firstDelimiter).Skip(columnIndex).First().value
        .Split(secondDelimiter).Skip(subColumnIndex).First().value;

return map newTable as 
    [id: parseFunction(rowName, 0, 1),
     price: parseFunction(rowName, 1, 1), 
     name: parseFunction(rowName, 2, 1)];
```
