【问题标题】:In F#, what does pipelining mean?在 F# 中,流水线是什么意思?
【发布时间】:2011-01-11 17:41:09
【问题描述】:

我正在阅读 Tomas Petricek 的这篇文章,其中提到了流水线 |>,如给出的示例所示:

> 让 nums = [1; 2; 3; 4; 5];; val nums : 列表 > 让赔率加十 = 数字 |> List.filter (fun n-> n%2 0) |> List.map (加10) valodds_plus_ten : list = [11; 13; 15];;

流水线是什么意思?最初,我认为它类似于在内核中流水线化的 CPU 指令。你能解释一下它是什么以及它在 F# 的上下文中是如何工作的吗?

谢谢, 最好的祝福, 汤姆。

【问题讨论】:

  • 把它想象成 PowerShell 或传统 shell 中的管道(不过,考虑到传递对象,它实际上更类似于 PowerShell)。它与 CPU 管道没有直接关系:-)
  • @Johannes:你的意思是这样的...cat myfile | more,来自 one 的输入被传递到输出以由 more 处理?
  • 没错。尽管如前所述,UNIX shell 类比在这方面存在很大缺陷。

标签: f# functional-programming


【解决方案1】:

流水线意味着将一个函数的结果传递给另一个函数。在您给出的示例中,“nums”被传递给 List.Filter,过滤后的结果随后被传递给 List.Map。

更多信息在这里:http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6

【讨论】:

  • @Steve:感谢您的链接,将调查一下,一个快速的问题 - 流水线如何知道何时停止将信息从一个传递到下一个? :) 谢谢。
  • @Steve:这是一个很好的链接!一旦我完成了 Tomas Petricek 的文章,就把它加入书签吧!此刻,F# 交互式 shell 正在我这边煎熬……
  • 抱歉,我也刚接触 F#,所以我不确定我是否真的能回答您的后续问题。我不认为你可以“停止”流水线,我认为第一个函数的所有结果都会传递给下一个函数。
  • 酷!来自 Assembler/C/C# 背景,它确实会烧脑吧? :) 享受 F# 的学习.... :) 感谢您的回答!
  • 大声笑,是的,这是肯定的观点的一点改变。
【解决方案2】:

在某些方面,流水线没有什么特别之处;你可以写x |> h |> g |> f,而不是写f (g (h x)),这似乎不是一个明显的改进。但是,有两点值得牢记:

  1. 有时读取顺序对于流水线版本更好:“将 x 发送到 h,将结果发送到 g,将结果发送到 f”比“将 f 应用于应用 g 的结果”更容易理解将 h 应用于 x 的结果”。
  2. 对于流水线版本,类型推断通常效果更好。这可能是 F# 中如此多地使用流水线的最大原因。由于类型推断从左到右进行,x |> Array.map (fun s -> s.Length) 将在 x 为 string[] 时起作用,但 Array.map (fun s -> s.Length) x 不会;你需要改用Array.map (fun (s:string) -> s.Length) x

【讨论】:

    【解决方案3】:

    查看Pipelining in F# 以获得解释。

    (如果您熟悉 unix 命令行和管道,例如

    cat file1 | sort | head 
    

    这是一个类似的想法;前一个表达式的结果成为下一个函数的参数。)

    【讨论】:

      【解决方案4】:

      正如其他人所提到的,流水线更像是 UNIX shell 管道。它让您编写一些输入,然后是应该应用到它的操作,而不是通常的嵌套函数调用。在此示例中,标准 F# 代码如下所示:

      let r = List.map (add 10) (List.filter (fun n-> n%2 <> 0) nums)
      

      请注意,输入nums 深深嵌套在表达式中,不容易看出它是先过滤后投影的。使用流水线,您可以以不同的方式编写代码,但它的含义完全相同。

      诀窍在于流水线操作符使用中缀表示法获取两个参数(例如x |&gt; f)。 x 参数将作为最后一个参数传递给右侧的函数 (f)。您可以将流水线与任何 F# 函数一起使用:

      let sinOne = 1.0 |> sin
      
      let add a b = a + b
      let r = 10 |> add 5 // it doesn't always make code more readable :-)
      

      关于 F# 流水线操作符的重要一点是它不是该语言的任何特殊内置功能。它是一个简单的自定义运算符,您可以自己定义:

      let (|>) x f = f x
      
      // Thanks to operator associativity rules, the following:
      let r = 1.0 |> sin |> sqrt
      // ...means this:
      let r = (1.0 |> sin) |> sqrt
      

      【讨论】:

      • 让我大吃一惊的是,如此强大和有用的运算符的定义是如此微不足道。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 2020-03-03
      • 1970-01-01
      • 2016-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多