如何在F#中结合管道操作符使用Array.Sub函数?
首先,咱们得先搞清楚Array.sub的函数签名:它是'a array -> int -> int -> 'a array,也就是第一个参数必须是目标数组,接着是起始索引,最后是子数组的长度。这也是你之前两种写法失败的核心原因,咱们逐个分析:
为什么
a1 |> Array.sub 5 10不行?
F#的函数是柯里化的,Array.sub 5 10会尝试把5作为第一个参数(也就是数组参数)传入,但5是整数,根本不是数组类型,所以编译器直接报错。管道操作符|>是把左边的值作为第一个参数传给右边的函数,但这里右边的Array.sub 5 10本身就无法通过编译,更别说接收管道传来的数组了。为什么
a1 5 10 ||> Array.sub不行?
二元管道||>的作用是把左边的二元组作为函数的前两个参数传入,比如(x, y) ||> f等价于f x y。但你这里写的a1 5 10根本不是合法的二元组语法,语法上就不成立,自然无法运行。
接下来给你几种可行的实现方式,按直观程度排序:
方法1:使用Lambda表达式包裹(最直观)
直接用lambda把管道传来的数组作为Array.sub的第一个参数,剩下的索引和长度直接填进去就行:
let a1 = [| 0 .. 99 |] let a2 = a1 |> fun arr -> Array.sub arr 5 10 printfn "%A" a2 // 输出 [|5; 6; 7; 8; 9; 10; 11; 12; 13; 14|]
方法2:使用flip函数调整参数顺序
如果你的场景中需要多次用管道调用类似的函数,可以定义一个flip3函数来调整三元函数的参数顺序,把数组参数放到最后,这样就能用管道传递了:
let flip3 f x y z = f z x y // 针对三元函数,把第一个参数放到最后 let a1 = [| 0 .. 99 |] // 用flip3调整Array.sub的参数顺序,让数组变成最后一个参数 let a2 = a1 |> flip3 Array.sub 5 10 printfn "%A" a2 // 结果和上面一致
方法3:部分应用后再传递数组
先构建一个接收索引、长度和数组的函数,再通过管道传递数组:
let a1 = [| 0 .. 99 |] let getSubArray start len arr = Array.sub arr start len let a2 = a1 |> getSubArray 5 10 printfn "%A" a2
这种写法本质上是自定义了一个参数顺序更适合管道的封装函数,可读性也不错。
总结一下,最常用的还是第一种lambda包裹的方式,简单直接,可读性也高。
内容的提问来源于stack exchange,提问作者Hasan A Yousef

