# 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)];
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.novacuraflow.com/development/flowscript/statements.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
