How does the fold function in the Seq module work?

If I want to append the values of each row from a table into a string seperated by commas, can I use the fold function? Usually we’d use the for loop or a select query in flowscript.

You can indeed use the fold function to join text values by some delimiter. Here’s an example of that:

open Seq;

let countries = ["Jordan", "Norway", "Mali"];

return countries.fold(
   "",
   (acc, next) => case when acc != "" then `{acc}, {next}` else next end
);

This will return "Jordan, Norway, Mali". But in this case, the fold function would be overkill: return countries.join(", ") is a much simpler way of expressing the same thing.

Generally, the fold function (similar to “reduce” in Javascript) takes a sequence, a seed value and some folder function, usually given as a lambda expression. Intuitively we can think of it as starting from the seed value and then sucessively kneading each element of the list into a big dough – the result value. The folder function you provide decides exactly what this “kneading” entails.

To clarify how fold works, we might first change the example above by turning the lambda expression into a separate function:

open Seq;

let countries = ["Jordan", "Norway", "Mali"];

// Given a text list of countries (possibly empty) and a next country,
// add the next country to the list.
function F(countryList, nextCountry) {
    if countryList == "" {
        return nextCountry;
    }
    else {
        return `{countryList}, {nextCountry}`;
    }
}

// For example:
//   F("", "Sweden") = "Sweden"
//   F("China", "Laos") = "China, Laos"

return countries.fold("", F); // returns "Jordan, Norway, Mali"

The key to understanding fold is that it is, in this case, exactly equivalent to calling F(F(F("", "Jordan"), "Norway"), "Mali").

Thanks for the clarification. But if I want to build an html table body string where I append each row from a table in a loop, would the fold function be useful?

Eg:

let purchaseReqLinesTbl = [
    {
        requestLineNo: 1,
        qty: 2,
        chosenUOM: "PCS",
        chosenPartNo: 0,
        description: "Mouse",
        note: "https://docs.novacura.com/flow-connect/reference/reference/flowscript/walkthrough/seq-module#tolookup",
        receiptDate: Date("2025-03-21T00:00:00.0000000+05:30"),
        price: 200,
        chosenCurr: "SEK"
    },
    {
        requestLineNo: 3,
        qty: 2,
        chosenUOM: "PCS",
        chosenPartNo: 0,
        description: "phone",
        note: "https://docs.novacura.com/flow-connect/reference/reference/flowscript/walkthrough/seq-module#tolookup",
        receiptDate: Date("2025-03-21T00:00:00.0000000+05:30"),
        price: 300,
        chosenCurr: "USD"
    }
]
        
let mailHTMLBody = '<style>table, th, td {border: 1px solid black;}</style><TABLE style="width:100%"><tr><th>Quantity</th><th>UOM</th><th>Description</th><th>Price</th><th>Currency</th><th>Note</th></tr>'

for c in purchaseReqLinesTbl {
    set mailHTMLBody = mailHTMLBody & '<TR><TD>' & c.qty & '</TD><TD>' & c.chosenUOM & '</TD><TD>' & c.description & '</TD><TD>' & c.price & '</TD><TD>' & c.chosenCurr & '</TD><TD>' & c.note & '</TD></TR>'
}
set mailHTMLBody = mailHTMLBody & '</TABLE>';
return mailHTMLBody

Thank you for the detailed example. I don’t think fold is applicable here. I would solve it using a combination of map and join:


open Seq;

// Make a variadic function which creates a TR with any number of TDs.
// For example, TR("hello", "world") --> <TR><TD>hello</TD><TD>world</TD></TR>

function TR(...cells: text*) {
    return "<TR>" & cells.map(c => `<TD>{c}</TD>`).join("") & "</TR>"
}

let rows = purchaseReqLinesTbl.map(r => TR(r.qty, r.chosenUOM, r.description, r.price, r.chosenCurr, r.note));

return mailHTMLBody & rows.join("") & "</TABLE>";

Alright, makes sense. Thanks!