FSharp.Core 中"id"函数的目的是什么?



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 传递,如果不是类型为"字符串选项",则会引发错误。

现在有一个提供盒装输出值的函数,可以是

  1. 'a ->任何类型,但没有选择
  2. 'b -> 'x 选项

为了正确框住值,我使用

val |> if isOption then fnOptTransform else id

所以我应用了高阶函数fnOptTransform,并通过以其他方式调用id,避免了编写单独 lambda 的丑陋(我尽量避免它,在我可以的地方......发现它很有用。

相关内容

  • 没有找到相关文章