为什么管道操作员工作?

use*_*138 12 f#

如果管道运算符是这样创建的:

let (|>) f g = g f
Run Code Online (Sandbox Code Playgroud)

像这样使用:

let result = [2;4;6] |> List.map (fun x -> x * x * x)
Run Code Online (Sandbox Code Playgroud)

那么它似乎做的是将List.Map放在后面(有趣的x - > x*x*x)并且不会改变[2; 4; 6]的位置

所以现在它看起来像这样:

let result2 = [2;4;6] (fun x -> x * x * x) List.map
Run Code Online (Sandbox Code Playgroud)

但这不起作用.

我现在第一次学习f#.这在读一本关于f#的书时困扰着我.所以我可能会知道我后来失踪的东西,但无论如何我决定问.

很明显,我错过了一些重要的东西.因为我可以轻松地重新创建管道操作员.但我不明白为什么它有效.当我了解更多信息时,我可能很快就会为自己感到尴尬.那好吧.

N_A*_*N_A 15

管道运算符只是链式方法调用的语法糖.它与linq表达式在C#中的表达方式非常相似.

这里解释:

前进管道操作员我爱这个人.Forward管道运算符简单地定义为:

let (|>) x f = f x
Run Code Online (Sandbox Code Playgroud)

并有一个类型签名:

'a -> ('a -> 'b) -> 'b
Run Code Online (Sandbox Code Playgroud)

转换为:给定泛型类型'a,以及带'a并返回'b的函数,然后在输入上返回函数的应用程序.

让我举一个可以使用它的例子,而不是解释这个:

// Take a number, square it, then convert it to a string, then reverse that string
let square x         = x * x
let toStr (x : int)  = x.ToString()
let rev   (x : string) = new String(Array.rev (x.ToCharArray()))

// 512 -> 1024 -> "1024" -> "4201"
let result = rev (toStr (square 512))
Run Code Online (Sandbox Code Playgroud)

代码非常简单,但请注意语法看起来多么不守规矩.我们要做的就是获取一次计算的结果并将其传递给下一次计算.我们可以通过引入一系列新变量来重写它:

let step1 = square 512
let step2 = toStr step1
let step3 = rev step2
let result = step3
Run Code Online (Sandbox Code Playgroud)

但现在你需要保持所有这些临时变量.(|>)运算符的作用是获取一个值,并将其"转发"给函数,本质上允许您在函数调用之前指定函数的参数.这大大简化了F#代码,允许您将函数一起管道,其中一个函数的结果传递到下一个函数.因此,要使用相同的示例,代码可以清楚地写为:

let result = 512 |> square |> toStr |> rev
Run Code Online (Sandbox Code Playgroud)

编辑:

在F#中,你真正使用方法调用正在执行一个函数然后将它应用于后面的参数,所以在你的例子中它将被List.map (fun x -> x * x * x)应用于[2;4;6].管道操作员所做的就是以相反的顺序获取参数,然后将应用程序反转回来.

功能:List.map (fun x -> x * x * x) 参数:[2;4;6]

标准F#调用语法:fg

反转F#调用语法:gf

标准:

let var = List.map (fun x -> x * x * x) [2;4;6]
Run Code Online (Sandbox Code Playgroud)

相反:

let var = [2;4;6] |> List.map (fun x -> x * x * x)
Run Code Online (Sandbox Code Playgroud)

  • 哦,我看到你被绊倒的地方.`List.map`是一个curried函数,它返回一个函数并接受两个参数:一个函数和一个列表.`List.map(fun x - > x*x*x)`返回一个只占用列表的新方法.因此,在您的示例中,您将从`List.map(fun x - > x*x*x)`的调用返回的函数应用于您的列表. (4认同)
  • 虽然这是一个很好的例子,我很困惑,为什么没有人指出,在过去的四年是`方512`是`262144`,不`1024`. (3认同)
  • @DavidArno 这是个好问题。现在我应该改变它以使其更正确还是因为它有趣而离开它? (2认同)
  • 我会离开它。正如您所说,这很有趣,并且不会减损它仍然是一个很好的答案的事实。 (2认同)

Lee*_*Lee 8

括号|>表示它是一个中缀运算符,因此可以编写您的示例

let result = (|>) [2;4;6] (List.map (fun x -> x * x * x))
Run Code Online (Sandbox Code Playgroud)

由于|>将第一个参数应用于第二个参数,这相当于

let result = (List.map (fun x -> x * x)) [2;4;6]
Run Code Online (Sandbox Code Playgroud)


Ono*_*cci 5

正如其他人上面所说,基本上你误解了结果2会解决的问题.它实际上会解决

List.map (fun x -> x * x * x) [2;4;6]

List.map有两个参数:一个应用于列表中所有元素的函数和一个列表. (fun x -> x * x * x)是第一个参数,[2;4;6]是第二个参数.

基本上只是把右边的东西放在左边|>的东西上.

  • 很高兴您对争论顺序更加明确,"......结束后"......任何来到F#游戏后期看到Elixir的`|>`的人都会被绊倒,因为它适用于价值在左边作为_first_参数. (2认同)