I will try to clarify what I said in my comments. You are right that your assign definition is excellent, and it looks like it has the signature byref<'a> -> 'a -> unit . However, if you look at the final assembly, you will find that the method compiled at the .NET presentation level:
Void assign[a](a ByRef, a)
(i.e. this is a method that takes two arguments and returns nothing, not the value of a function that takes one argument and returns a function that takes the next argument and returns a value of type unit - the compiler uses some additional metadata to determine how this method was actually declared).
The same applies to function definitions that are not related to byref . For example, suppose you have the following definition:
let someFunc (x:int) (y:string) = ()
Then the compiler actually creates a method with a signature
Void someFunc(Int32, System.String)
The compiler is smart enough to do the right thing when you try to use a function like someFunc as a first class value - if you use it in a context where it does not apply to any arguments, the compiler will generate a subtype int -> string -> unit ( which is FSharpFunc<int, FSharpFunc<string, unit>> at the .NET view level) and everything works without problems.
However, if you try to do the same with assign , this will not work (or should not work, but there are some compiler errors that may make it seem that some variations work when they really don't work, t - you may not get a compiler error, but you may get an assembly of results that was malformed). It is not legal for instances of type .NET to use byref types as arguments of a general type, therefore FSharpFunc<int byref, FSharpFunc<int, unit>> not valid. NET The fundamental way that F # represents function values ββjust doesn't work when there are byref arguments.
So, a workaround is to create your own type using a method that takes a byref argument, and then create subtypes / instances that have the behavior you want, like manually doing what the compiler does automatically in a non-t24> case. You can do this with a named type
type MyByrefFunc2<'a,'b> = abstract Invoke : 'a byref * 'b -> unit let assign = { new MyByrefFunc2<_,_> with member this.Invoke(result, x) = result <- x }
or with delegation type
type MyByrefDelegate2<'a,'b> = delegate of 'a byref * 'b -> unit let assign = MyByrefDelegate2(fun result x -> result <- x)
Please note that when calling methods such as Invoke in a delegate or nominal type, the actual tuple is not created, so you should not worry about any additional overhead (this is a .NET method that takes two arguments and is processed as such by the compiler) . There is the cost of invoking a virtual method or delegation, but in most cases similar costs exist when using function values ββin the first class. And in general, if you are worried about performance, you should set a goal and measure it, and not try to optimize prematurely.