I have looked far and wide for an answer to this but have exhausted all attempts.
I want to override a custom operator already defined in a project, the classic compose >=> operator, such that if it is used with my class type, it will use its static operator overload instead but every time I use the class with the >=> operator, it gives me error that my class is not compatible with global operator definition. to help explain:
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) = ...
This is so that I may write code that can wrap the composed handlers like
// 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
]
But unfortunately, the static method overloads on the class cannot override the global operator and take precedence ... is there anything I can do to override the global operator to make this work!? ... I know I can change my Handle from a type augmentation to a full class implementation, remove global operator and use only static overrides on the two classes but to integrate with the existing framework i'm looking at, needs to be a function of this format ...
I was thinking of perhaps overloading FSharpFunc> with static member (>=>) but in f# this would need to be declared in the original declaration location which is off limits.
I looked into claimed way in c# to override with overload operator using virtual methods but this didn't seem to work.
All this Hacking (for want of a better word) is to maintain the compose operator format while using a Node class to store these handlers to build into a Node tree. The fact that the child lists are optional means that although I could overload the constructor using tuples of (key, composedHandlers) / (key, composedHandlers, ChildList), this would be too ugly and wrapped to be accepted ie:
let node1 = Node ("key1", handle1 >=> handle2 , [
Node ("key2",handle3 >=> handle4, [
Node ("key3",handle5)
])
])
I could change the class static operator to something like => / ==> but then it causes confusion as to when to use >=> or use =>, it's too much to ask a user to figure out if handlers are feeding into a node or are they purely composing two handlers into one.
If statically resolved type conditions were not locked to only Core I could do something like the following ... but not allowed:
let (>=>) (a:^T) (b:Handler)
when ^T : Handler = ...
when ^T : Node = ...
when ^T : Node list = ...
The issue boils down to, How can I make operator type conditional or how can I make an overloaded class operator override a global operator so that I can use both together depending on the infix types.
---EDIT---
@Gustavo linked post was exactly what I was looking for:
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