From Operators.id<'T> 函数 (F#):
标识函数。
参数:x 类型:'t(输入值)
返回值:相同的值
F# 核心库版本,支持:2.0、4.0、可移植
为什么有一个函数返回其输入?
当使用高阶函数(即返回其他函数和/或将其他函数作为参数的函数)时,始终必须提供一些内容作为参数,但并不总是要应用实际的数据转换。
例如,该函数Seq.collect
展平序列序列,并采用一个函数,该函数返回"外部"序列的每个元素的"嵌套"序列。例如,您可以通过这种方式获取某种 UI 控件的所有子项的列表:
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
它对于某些高阶函数(将函数作为参数的函数)很有用,因此您可以将id
作为参数传递,而不是写出lambda(fun x -> x)
。
[[1;2]; [3]] |> List.collect id // [1; 2; 3]
它在使用选项时非常有用。
我写了一个小的习惯性 JSON 助手,将所有可选字段指示为 Option,如果字符串作为 null 传递,如果不是类型为"字符串选项",则会引发错误。
现在有一个提供盒装输出值的函数,可以是
- 'a ->任何类型,但没有选择
- 'b -> 'x 选项
为了正确框住值,我使用
val |> if isOption then fnOptTransform else id
所以我应用了高阶函数fnOptTransform,并通过以其他方式调用id,避免了编写单独 lambda 的丑陋(我尽量避免它,在我可以的地方......发现它很有用。