【发布时间】:2020-08-04 06:05:04
【问题描述】:
我正在尝试创建一个中缀运算符以使 System.Text.StringBuilder 更易于使用。
我有以下使用静态解析类型参数的内联函数:
let inline append value builder = (^T : (member Append : _ -> ^T) (builder, value))
它处理StringBuilder.Append 的所有重载。这可以作为常规功能正常工作:
StringBuilder()
|> append 1
|> append " hello "
|> append 2m
|> string
// Result is: '1 hello 2'
当我尝试使用这样定义中缀运算符时:
let inline (<<) builder value = append value builder
当链中的所有参数都属于同一类型时,它可以工作:
StringBuilder()
<< 1
<< 2
<< 3
|> string
// Result is: '123'
但使用不同类型的参数失败:
StringBuilder()
<< 1
<< "2" // <- Syntax error, expected type 'int' but got 'string'.
<< 123m // <- Syntax error, expected type 'int' but got 'decimal'.
预期的类型似乎是通过链中<< 运算符的第一次使用推断出来的。我假设每个<< 都将单独应用。
如果链被分成单独的步骤,编译器会再次高兴:
let b0 = StringBuilder()
let b1 = b0 << 1
let b2 = b1 << "2"
let b3 = b2 << 123m
b3 |> string
// Result is: '12123'
有没有可能创建这样的算子?
编辑
一个 hacky 的“解决方案”似乎是只要参数的类型发生变化,就通过 identity 函数传递中间结果:
StringBuilder()
<< 1 // No piping needed here due to same type (int)
<< 2 |> id
<< "A" |> id
<< 123m
|> string
// Result is: '12A123'
【问题讨论】: