我可以使用F#中的管道运算符将参数传递给构造函数吗?

roy*_*yco 7 f#

此代码反转字符串:

let reverse (s : string) = new string(s.ToCharArray() |> Array.rev)
Run Code Online (Sandbox Code Playgroud)

可以使用管道运算符重写它以将所需的参数传递给string()构造函数吗?例如,这似乎更惯用:

// Doesn't compile:
let reverse (s : string) = s.ToCharArray() |> Array.rev |> new string
Run Code Online (Sandbox Code Playgroud)

同样,为什么我不能string以下列方式使用运算符?

let reverse2 (s : string) = s.ToCharArray() |> Array.rev |> string
Run Code Online (Sandbox Code Playgroud)

这是在行动:

> reverse2 "foo" ;;
val it : string = "System.Char[]"
Run Code Online (Sandbox Code Playgroud)

它返回的类型而不是"oof".

Ste*_*sen 9

不,管道运算符只能与F#函数一起使用,它不能与类构造函数,成员方法或静态方法一起使用.原因是这些方法支持的重载会使F#的类型推断复杂化.但是,如果您真的想使用管道,可以将char数组的每个元素映射到一个String,然后将该序列传递到Seq.concat "":

s.ToCharArray() |> Array.rev |> Seq.map(string) |> String.concat ""
Run Code Online (Sandbox Code Playgroud)

或者你可以用F#方法包装字符串构造函数调用:

let stringCArrCtor (carr: char[]) =
    new string(carr)

s.ToCharArray() |> Array.rev |> stringCArrCtor
Run Code Online (Sandbox Code Playgroud)

并回答你的上一个问题,

s.ToCharArray() |> Array.rev |> string
Run Code Online (Sandbox Code Playgroud)

不能使用,因为它相当于

(s.ToCharArray() |> Array.rev).ToString()
Run Code Online (Sandbox Code Playgroud)

并且不会覆盖Array ToString()方法,因此它只返回默认的反射类型名称.


Tom*_*cek 9

正如斯蒂芬所提到的,最好的办法是定义一个调用构造函数的新函数.您可以将它放入一个名为String(在某些命名空间中)的模块中,这样您就可以获得与使用其他F#函数时类似的感觉.我可能会用:

module String =
  let create (c:char[]) = new string(c)
Run Code Online (Sandbox Code Playgroud)

使用构造函数作为一等价值的问题出现在SO之前,但我不能再找到我之前的答案 - 有一个非常疯狂的技巧可以提供你的能力,但它是一个巨大的黑客(没有人应该使用它和一些F#的下一个版本希望不会允许这样做.无论如何,您可以使用静态解析的类型参数来编写以下内容:

let inline ctor< ^R, ^T when ^R : 
        (static member ``.ctor`` : ^T -> ^R)> (arg:^T) =
    (^R : (static member ``.ctor`` : ^T -> ^R) arg)
Run Code Online (Sandbox Code Playgroud)

并使用这样的功能:

"ABC".ToCharArray() |> Array.rev |> ctor<string, _>;;
Run Code Online (Sandbox Code Playgroud)

ctor函数本质上要求指定为第一个类型参数的类型具有构造函数,并且它调用构造函数(另一个类型参数是构造函数的参数,并由编译器推断).但这实际上只是一种好奇心 - 定义自己的功能是最好的方法.