我正在尝试创建一个中缀运算符以使其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'
是否可以创建这样的运算符?
一个变态的“解决方案”似乎是每当参数的类型更改时,就通过身份函数传递中间结果:
StringBuilder()
<< 1 // No piping needed here due to same type (int)
<< 2 |> id
<< "A" |> id
<< 123m
|> string
// Result is: '12A123'
尽管我只能推测此行为可能与的特定重载有关,但我可以为这个谜题添加一个数据点value: obj
。如果我取消注释该行并尝试运行它,则编译器会说:
Script1.fsx(21,14): error FS0001: Type mismatch. Expecting a 'a -> 'c but given a System.Text.StringBuilder -> System.Text.StringBuilder The type ''a' does not match the type 'System.Text.StringBuilder'
这是在尝试将System.Text.StringBuilder
运算符的各种重载映射到静态解析的类型参数时发生的。在类似情况下,这似乎是一种相当标准的技术,因为它会为不受支持的类型产生编译时错误。
open System.Text
type Foo = Foo with
static member ($) (Foo, x : bool) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : byte) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : char[]) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : char) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : decimal) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : float) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : float32) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : int16) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : int32) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : int64) = fun (b : StringBuilder) -> b.Append x
// static member ($) (Foo, x : obj) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : sbyte) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : string) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : uint16) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : uint32) = fun (b : StringBuilder) -> b.Append x
static member ($) (Foo, x : uint64) = fun (b : StringBuilder) -> b.Append x
let inline (<.<) b a =
(Foo $ a) b
// val inline ( <.< ) :
// b:'a -> a: ^b -> 'c
// when (Foo or ^b) : (static member ( $ ) : Foo * ^b -> 'a -> 'c)
let res =
StringBuilder()
<.< 1
<.< 2
<.< 3
<.< "af"
<.< 2.32m
|> string
// val res : string = "123af2,32"
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句