Ответ 1
При работе с функциями более высокого порядка (т.е. функциями, возвращающими другие функции и/или принимающими другие функции в качестве параметров), вы всегда должны предоставлять что-то в качестве параметра, но не всегда есть фактическое преобразование данных, которое вы хотите подать заявку.
Например, функция Seq.collect
выравнивает последовательность последовательностей и берет функцию, которая возвращает "вложенную" последовательность для каждого элемента "внешней" последовательности. Например, так вы можете получить список всех внуков элемента управления пользовательского интерфейса:
let control = ...
let allGrandChildren = control.Children |> Seq.collect (fun c -> c.Children)
Но много раз каждый элемент последовательности уже будет последовательностью сам по себе - например, у вас может быть список списков:
let l = [ [1;2]; [3;4]; [5;6] ]
В этом случае функция параметров, которую вы передаете на Seq.collect
, должна просто вернуть аргумент:
let flattened = [ [1;2]; [3;4]; [5;6] ] |> Seq.collect (fun x -> x)
Это выражение fun x -> x
- это функция, которая просто возвращает свой аргумент, также известный как "функция идентификации".
let flattened = [ [1;2]; [3;4]; [5;6] ] |> Seq.collect id
Его использование часто возникает при работе с функциями более высокого порядка (например, Seq.collect
выше), которые он заслуживает места в стандартной библиотеке.
Другим убедительным примером является Seq.choose
- функция, которая фильтрует последовательность значений Option
и разворачивает их в одно и то же время. Например, так вы можете анализировать все строки как числа и отбрасывать те, которые не могут быть проанализированы:
let tryParse s = match System.Int32.TryParse s with | true, x -> Some x | _ -> None
let strings = [ "1"; "2"; "foo"; "42" ]
let numbers = strings |> Seq.choose tryParse // numbers = [1;2;42]
Но что, если вам уже дали список значений Option
для начала? Функция идентификации для спасения!
let toNumbers optionNumbers =
optionNumbers |> Seq.choose id