F#: String.Join 和 |> 运算符

55

在 F# 交互式中,我可以成功地使用 String.Join("+", ["a"; "b"]),但是

["a"; "b"] |> String.Join "+"

会产生一个错误:

Script1.fsx(79,15): error FS0001: This expression was expected to have type
    string list -> 'a    
but here has type
    string

我该如何使用 String.Join 并通过管道传递集合?

P.S. lines |> File.WriteAllLines "filename.txt" 也存在相同的问题。

2个回答

86

String.Join是.NET方法。在使用.NET方法时,F#将其视为接受元组作为参数的函数(调用时将参数写成f(a, b))。|>操作符可用于使用柯里化形式参数的函数(可以通过写f a b来调用)。

你可以使用F#库中的函数String.concat(执行相同的操作)代替它:

["a"; "b"] |> String.concat "+"

编辑 File.WriteAllLines 也是同样的情况。如果你想把它作为管道的一部分使用,可以编写一个包装该调用的 F# 函数:

let writeAllLines file (lines:seq<string>) =
  System.IO.File.WriteAllLines(file, lines)

通常情况下,你只能在.NET方法中使用|>运算符,如果你想将所有参数都写在运算符的左侧。例如,你可以这样写:

("+", ["a"; "b"]) |> System.String.Join

...但这并不符合管道运算符的通常用法。当与.NET API一起使用时,通常最好使用类似C#编程风格(不使用管道),因为管道只适用于函数式库。


我认为它应该是 ("+",[|"a","b"|]) |> System.String.Join,接受一个字符串数组。不过这并不重要,它仍然让我的眼睛难受。 - cfern
1
@cfern:我认为原始代码也可以,因为有一个重载函数接受seq<string> - Tomas Petricek
1
@Tomas Petricek:IEnumerable重载仅存在于.Net 4中(这就解释了为什么在VS2008中它对我无效)。今天我学到了新东西。 :) - cfern
@cfem:有趣,谢谢分享。我也学到了一些东西 :-) - Tomas Petricek
我创建了一个项目,它是围绕BCL静态方法ComposableExtensions的内联函数集合。 - jbtule
显示剩余2条评论

24

我想提供另一种选择。OP特别询问了String.Join方法,Tomas Petricek的答案对于该方法是完全正确的(使用F#库中的String.concat)。

如果您要讨论其他需要用作柯里化的元组参数的方法,则可以使用此辅助函数:

let partial f x y = f(x, y)

这使您能够将方法传递给“partial”并返回一个柯里化的函数。使用方法如下:
let partial f x y = f(x, y)
myCollection |> partial String.Join "&"

这个函数的一个好名字可能是“柯里化”;然后你也可以有“非柯里化”。 - Jwosty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接