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

Types F#:使用静态方法重载或类型条件运算符重写全局运算符,types,f#,operator-overloading,overriding,compose,Types,F#,Operator Overloading,Overriding,Compose,我已经到处寻找答案,但已经用尽了所有的努力 我想覆盖一个已经在项目中定义的自定义运算符,即经典的compose=>运算符,这样,如果它与我的类类型一起使用,它将使用其静态运算符重载,但每次我使用带有=>运算符的类时,它给了我一个错误,我的类与全局运算符定义不兼容。要帮助解释: type Handler = context -> context option // context just placeholder for type let (>=>) (a:Handler) (

我已经到处寻找答案,但已经用尽了所有的努力

我想覆盖一个已经在项目中定义的自定义运算符,即经典的compose
=>
运算符,这样,如果它与我的类类型一起使用,它将使用其静态运算符重载,但每次我使用带有
=>
运算符的类时,它给了我一个错误,我的类与全局运算符定义不兼容。要帮助解释:

type Handler = context -> context option // context just placeholder for type

let (>=>) (a:Handler) (b:Handler) = fun ctx -> match a ctx with | Some u -> b u | None

type Node(key) =
...
member static (>=>) (p:Node,h:Handler) = ...
member static (>=>) (p:Node,pl Node list) = ...
这样我就可以编写代码来包装组合处理程序,如

// val Node = Node (overloaded >=>) Handler (overloaded >=>) Handler (overloaded >=>) [ ... ]
let node = Node "key1" >=> handler1 >=> hander2 >=> [
                                Node "key2" >=> handler3
// val Handler = Handler (global >=>) Handler
let handler3 = handler1 >=> handler2 
                                ]
但不幸的是,类上的静态方法重载不能重写全局运算符并优先。。。我可以做些什么来覆盖全局运算符以使其工作。。。我知道我可以将我的句柄从一个类型扩充更改为一个完整的类实现,删除全局运算符,并且只在两个类上使用静态重写,但是要与我正在查看的现有框架集成,需要使用这种格式的函数

我想用静态成员(>=>)重载FSharpFunc>,但在f#中,这需要在禁止使用的原始声明位置声明

我研究了c#中使用虚拟方法用重载操作符重写的方法,但这似乎不起作用

所有这些黑客行为(因为缺少更好的词)都是为了在使用节点类存储这些处理程序以构建节点树的同时维护compose操作符格式。子列表是可选的这一事实意味着,尽管我可以使用
(key,composedHandlers)
/
(key,composedHandlers,ChildList)
的元组重载构造函数,但这太难看了,包装得无法接受,即:

let node1 = Node ("key1", handle1 >=> handle2 , [
                                        Node ("key2",handle3 >=> handle4, [
                                                                    Node ("key3",handle5)
                                                                    ])
                                                ])
我可以将类静态运算符更改为类似于
=>
/
=>
的内容,但这样会导致混淆,即何时使用
=>
或何时使用
=>
,让用户弄清楚处理程序是馈送到一个节点中,还是纯粹将两个处理程序组合成一个处理程序,这太难了

如果静态解析的类型条件不是只锁定到Core,我可以执行如下操作。。。但不允许:

let (>=>) (a:^T) (b:Handler)
     when ^T : Handler   = ...
     when ^T : Node      = ...
     when ^T : Node list = ...
问题归结为,如何使运算符类型有条件,或者如何使重载的类运算符重写全局运算符,以便根据中缀类型将两者一起使用

---编辑---

@Gustavo链接的帖子正是我想要的:

type ComposeExtension = ComposeExtension with
    static member        (?<-) (ComposeExtension, (a:PathNode) , (b:HttpHandler)) = a.AddHandler b
    static member        (?<-) (ComposeExtension, (a:PathNode) , (b:PathNode list)) = a.AddChildPaths b
    static member inline (?<-) (ComposeExtension, a , b) = a >=> b
let inline (>=>) a b = (?<-) ComposeExtension a b
键入ComposeExtension=ComposeExtension和

静态成员(?=>)a b=(?我认为没有一种方法可以完全满足您的要求,但是如果您的目标是生成一个好看的DSL,那么您可以采用稍微不同的方法:将“just node”案例和“node with handlers applied”案例包装到DU中,然后在该DU上定义运算符:

type Handler = context -> context option
type Node = Node of key:string
type Composable = CNode of Node | CHandled of Handler

let node key = CNode (Node key)

let inline (>=>) (a:Composable) (b:Handler) = 
    match a with
    | CNode n -> ...
    | CHandled h -> ...

// Usage:
let handler1 = fun ctx -> ...
let handler2 = fun ctx -> ...

let a = node "abc" >=> handler1 >=> handler2
这在语法上起作用,并且与您的原始签名相匹配,但我必须说,这在我看来有点荒谬,这是因为我不太明白您的最终目标是什么:什么是
节点
?为什么需要“处理”?处理的结果是什么?从您的代码来看,它看起来像是“处理”的结果是另一个“处理者”,但这是正确的吗?等等

如果你能更好地澄清你的领域,我相信我们能想出一个更好的解决方案。

我对的回答说明了如何重新连接全球运营商

如果你发布一个最小的复制,我可以告诉你如何将它应用到你的案例中

话虽如此,我还是建议使用已经包含运算符
=>
的函数的函数,要使它与类一起工作,您所要做的就是定义
Bind
Return
,如下所示:

static member Return a = ...
static member Bind  (x, f) = ...

同样,如果你给我看你的代码,我可以提供更多的细节。

你在上一篇文章中的解决方案正是我想要的,非常感谢!!!我能够处理所有这三种情况!!感谢你的帮助,我试图避免用DU包装,因为
b
第二个变量也可以是
节点列表
,这样所有子变量链中的OUNT处理程序也需要包装,这只会使整个事情变得混乱。请注意,节点的上下文有点模糊,因此表示歉意。