使用静态解析的类型参数链接中缀运算符

peder86

我正在尝试创建一个中缀运算符以使其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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用参数创建中缀运算符

来自分类Dev

缺少参数的中缀运算符

来自分类Dev

F#三参数中缀运算符

来自分类Dev

“:-”中缀运算符的名称

来自分类Dev

F#:使用静态方法重载或类型条件运算符覆盖全局运算符

来自分类Dev

使用perl的eq运算符会更改参数的类型

来自分类Dev

Haskell美元运算符和中缀运算符

来自分类Dev

对部分应用的中缀运算符的困惑

来自分类Dev

充当无管道的中缀运算符?

来自分类Dev

Scala - super 的中缀运算符不能称为中缀

来自分类Dev

链接++运算符

来自分类Dev

链接“是”运算符

来自分类Dev

通过范围解析运算符调用非静态方法

来自分类Dev

在函数参数中使用<<运算符

来自分类Dev

使用扩展运算符作为参数

来自分类Dev

如何在Xor中正确使用'/ ='haskell中缀运算符?

来自分类Dev

使用带有中缀运算符的显式命名空间

来自分类Dev

在链接的 SQL Server 表上使用参数访问查询 Like 运算符

来自分类Dev

在C ++中使用带有const类型输入参数的函数内部使用运算符重载

来自分类Dev

为什么不能使用'as'运算符来解析不可为空的值类型?

来自分类Dev

如何创建%between%运算符之间的中缀?

来自分类Dev

为什么允许:=作为中缀运算符?

来自分类Dev

在Scala中创建中缀运算符

来自分类Dev

多个运算符的评估顺序以中缀形式

来自分类Dev

如何在R中查找中缀运算符的文档?

来自分类Dev

Haskell中的中缀运算符优先级

来自分类Dev

Haskell:中缀(`:`)运算符是否具有左侧标识?

来自分类Dev

groovy dsl-中缀运算符可能吗?

来自分类Dev

重新定义中缀运算符的特征