Списки могут быть объединены. Чтобы объединить два списка в один, используется функция List.append. Чтобы объединить больше двух списков, используется функция List.concat.
Операции сворачивания и сканирования похожи на функции List.iter и List.map в том, что функция вызывается по каждому элементу, но включают дополнительный параметр, который называется аккумулятор и содержит результат вычисления. List.fold можно использовать для выполнения расчетов со списком.
В следующем коде показано использование функции List.fold для выполнения различных операций. Лист обходится. Аккумулятор acc — это значение, которое передается дальше, пока продолжается расчет. Первый аргумент забирает аккумулятор и элемент списка и возвращает промежуточный результат расчета для этого элемента списка. Второй аргумент является исходным значением аккумулятора.
let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum
Функция List.scan отличается тем, что List.fold возвращает конечное значение дополнительного параметра, а List.scan — список промежуточных значений (наравне с конечным значением) дополнительного параметра. Каждая из этих функций включает обратную вариацию, например List.foldBack, и отличается в порядке обхода списка и в порядке аргументов. Кроме того, функции List.fold и List.foldBack имеют вариации, List.fold2 и List.foldBack2, которые берут два списка одинаковой длины. Функция, которая выполняется по каждому элементу, может использовать соответствующие элементы обоих списков для выполнения некоторых действий. Типы элементов этих списков могут отличаться, как в следующем примере, где один список содержит суммы транзакций на банковском счете, а другой — типы транзакций (внесение или снятие).
type Transaction =
| Deposit
| Withdrawal
let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
match elem1 with
| Deposit -> acc + elem2
| Withdrawal -> acc - elem2)
initialBalance
transactionTypes
transactionAmounts
printfn "%f" endingBalance
При расчете суммы функции List.fold и List.foldBack действуют одинаково, так как результат не зависит от порядка обхода. В следующем примере кода функцияList.foldBack используется для добавления элемента в список.
let sumListBack list = List.foldBack (fun acc elem -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])
В следующем примере снова используется банковский счет. В этот раз добавляется новый тип транзакций: расчет процентов. Конечный баланс теперь зависит от порядка транзакций.
type Transaction2 =
| Deposit
| Withdrawal
| Interest
let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
match elem1 with
| Deposit -> acc + elem2
| Withdrawal -> acc - elem2
| Interest -> acc * (1.0 + elem2))
initialBalance2
transactionTypes2
transactionAmounts2
printfn "%f" endingBalance2
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
match elem1 with
| Deposit -> acc + elem2
| Withdrawal -> acc - elem2
| Interest -> acc * (1.0 + elem2))
transactionTypes2
transactionAmounts2
initialBalance2
printfn "%f" endingBalance3
Функция List.reduce похожа на функцию List.fold и List.scan за тем исключением, что вместо передачи отдельного аккумулятора List.reduce использует функцию, которая берет два аргумента типа элемента вместо одного, и один из таких аргументов играет роль аккумулятора, т. е. хранит промежуточный результат вычисления.List.reduce начинает работу с первых двух элементов списка, а затем использует результат операции вместе со следующим элементом. Так как здесь нет отдельного аккумулятора с собственным типом, функция List.reduce может использоваться вместо List.fold только в том случае, если аккумулятор и элемент имеют одинаковые типы. В следующем коде показано использование функции List.reduce. List.reduce выводит исключение, если в списке нет элементов.
В следующем коде первый вызов выражения лямбда дает аргументы 2 и 4 и возвращает 6. В следующем вызове даются аргументы 6 и 10 и возвращается результат 16.