A sequence is a composite data type representing an ordered list of values. If you are familiar with other programming languages, you may recognize sequences as "lists", "arrays", or (in some cases) "tables".
Creating sequences
Sequences may be created using sequence expressions, comprising of an opening square bracket, a comma-separated list of elements, and a closing square bracket.
// Example: Create a sequence of numberslet xs = [1,2,3];// Exemple: Create a sequence of recordslet animals = [ { name:"Eurasian lynx", latinName:"Lynx lynx" }, { name:"Wolverine", latinName:"Gulo gulo" }];
A sequence of records is known, by convention, as a table.
You can also update (or rather, create an updated copy) of a sequence of records using the withkeyword.
// Example: create a sequence of cities and then create an updated copy.let cities = [ { name:"Stockholm", country:"Sweden" }, { name:"Esch-sur-Alzette", country:"Luxembourg" },];return cities with { countryCode:upper(left(country,3)) };
A with-expression may employ a guard expression to selectively update records:
let measurements = [ { temperature:7, unit:"Celsius" }, { temperature:53, unit:"Fahrenheit" },]// Example: convert all Fahrenheit measurements to Celsiusreturn measurements with { temperature: (temperature -32) *5/9, unit:"Celsius"} when unit ="Fahrenheit";
Several update clauses may be specified in a comma-separated list. The first clause whose guard expression is true for a record will be used to update that record. The otherwise guard expression always evaluates to true and must come last.
let distances = [ { value:10, unit:"feet" }, { value:67, unit:"centimeters" }]// Example: convert all measurements to metersreturn distanceswith { value:0.3048* value, unit:"meters" } when unit =="feet", { value: value /100, unit:"meters" } otherwise;
Accessing columns
For sequences of records, it is possible to access each "column" by dot notation. This will return a sequence containing the value of the member on each element.
The nameof a sequence type – as shown when you let the mouse cursor hover over a variable name in the Flow Designer – is created by appending an asterisk (*) to the type of the sequence's elements. In the example above, the variable xs contains numbers and thereforehas the type number* (pronounced "sequence of numbers"). The variable animals has the type {name: text, latinName: text}* which is slightly more difficult to pronounce.
Advanced: The type of an empty sequence
The type of a sequence is inferred from its elements. What, then, is the type of an empty sequence? Since there are no elements from which to infer an element type, FlowScript will choose the type nothing* for such a sequence. In conjunction with type evolution and subtyping rules, this ensures that the type of the empty sequence behaves well when combining with other, non-empty values.
let xs = []; // Here, xs has type nothing*set xs = xs & [1,2]; // Now, xs has type number*
Advanced: Mixed-type sequences
What if we create a sequence where the elements have different types? In that case, the element type of the sequence will be the lowest common supertype of all the elements.
// Example: create two sequences where the elements have different types.let mix1 = [ { name:"Red fox", latinName:"Vulpes vulpes" }, { name:"Yeti" } // Note: second item has no 'latinName' member]let mix2 = [1,2, {name:"Panther"}];
In the example above, mix1 has the type {name: text}*, which is the most useful common type for all the elements, and mix2 has the type unknown*, signalling that the elements have nothing at all in common.
Although the type of mix1 does not indicate the presence of a member labelled latinName, the member has not been erased. You can use type narrowing to get it back:
// Example: use type narrowing to list the latin names in "mix1"// as defined in the previous example.let allLatinNames = [];for animal in mix1 {if animal is {latinName: text} { set allLatinNames = allLatinNames &animal.latinName; }}// allLatinNames == ["Vulpes vulpes"]