Under normal circumstances, F# functions can be converted to delegates by calling new DelegateType and passing in the function as an argument. But when the delegate contains byref parameter, this is not possible directly. For example the code:
type ActionByRef<'a> = delegate of 'a byref -> unit
let f (x:double byref) =
x <- 6.0
let x = ref 42.0
let d = new ActionByRef<_>(f)
won't compile, giving the following error:
This function value is being used to construct a delegate type whose signature includes a byref argument. You must use an explicit lambda expression taking 1 arguments.
Following the error, modifying the code to use
let d = new ActionByRef<_>(fun x -> f(&x))
works. But my question is: why is this necessary? Why won't F# allow the conversion from named function to this delegate, but conversion from lambda is fine?
I came upon this behavior when researching another question. I realize byref is meant only for compatibility with other .Net languages.
I think the problem is that byref<'T> is not an actual type in F# - it looks like a type (to make the language simpler), but it gets compiled to a parameter marked with the out flag. This means that byref<'T> can be only used in a place where the compiler can actually use the out flag.
The problem with function values is that you can construct function e.g. by partial application:
let foo (n:int) (b:byref<int>) =
b <- n
When you pass foo as an argument to a delegate constructor, it is a specific case of partial application (with no arguments), but partial application actually needs to construct a new method and then give that to the delegate:
type IntRefAction = delegate of byref<int> -> unit
let ac = IntRefAction(foo 5)
The compiler could be clever and generate new method with byref parameter (or out flag) and then pass that by reference to the actual function, but in general, there will be other compiler-generated method when you don't use the fun ... -> ... syntax. Handling this would add complexity and I think that's a relatively rare case, so the F# compiler doesn't do that and asks you to be more explicit...
Related
OK:
let em inp=sprintf"<em>%A</em>"inp
let bold inp=sprintf"<b>%A</b>"inp
printfn"%s"<|em"blabla"///<em>blabla</em>
Trying to define together (with compiling error):
let em2,bold2=
let tag a b=sprintf"<%s>%A</%s>"a b a
(fun inp->tag"em"inp),tag"b"
Error:
Value restriction. The value 'em2' has been inferred to have generic type
val em2 : ('_a -> string -> string)
Either make the arguments to 'em2' explicit or, if you do not intend for it to be generic, add a type annotation.F# Compiler(30)
I don't think this is going to work, because the F# compiler doesn't consider a tuple to be a "simple immutable value":
The compiler performs automatic generalization only on complete function definitions that have explicit arguments, and on simple immutable values.
This means that the compiler issues an error if you try to compile code that is not sufficiently constrained to be a specific type, but is also not generalizable. The error message for this problem refers to this restriction on automatic generalization for values as the value restriction.
Instead, I think you have to define them separately, like this:
let tag a b=sprintf"<%s>%A</%s>"a b a
let em2 inp=tag"em"inp
let bold2 b=tag"b"b
If your desire here is to hide the definition of tag, you can make it private.
I like the idea of centralizing the logic (here: HTML formatting) in a single factory function, to enforce the DRY principle.
Instead of fully hiding the tag factory function in a closure, we can hide it just from other modules, making it private which is usually enough encapsulation. After some renaming:
let private inside tag content = // 'a -> '-b -> string
$"<{tag}>{content}</{tag}>" // 👈 F# 5 interpolated string
Then, the usual way in F# to generate the specific function is through partial application. Since the current inside function is generic, we can't use the point free notation (meaning implicit parameter content) without loosing the generic type:
let em = inside "em" // ⚠️ obj -> string
We have 2 solutions:
Have explicit content parameter: let em content = inside "em" content but it's less elegant.
Change the signature of inside function and make all parameters of type string. In fact, the function inside does not care about the type of its parameters - it only cares about strings since it casts them to string implicitly using the ToString() method which can lead to bad surprises when calling this function.
let private inside tag content = // string -> string -> string
$"<%s{tag}>%s{content}</{tag}>" // 👈 %s to indicate parameters are strings
let em = inside "em" // string -> string
let strong = inside "strong"
I am trying to add a F#-style interface to a type, that has a byref return method.
Here's the code:
type IPool<'P, 'T when 'T: struct> =
abstract member GetReference: ITypedPointer<'P, 'T> -> byref<'T>
let Ref<'TPool, 'P, 'T when 'TPool :> IPool<'P, 'T>> (pool: 'TPool) pointer =
pool.GetReference pointer
Now to my surprise, a similar thing worked fine until I introduced IPool interface. Before that Ref itself contained an implementation like &pool.data.[idx], and worked fine.
I tried installing nightly build of F# Tools, cause latest release does not officially support byref returns, and PR to introduce them was recently completed: https://github.com/Microsoft/visualfsharp/pull/4888
However, I still get error FS3209: The address of the variable 'copyOfStruct' cannot be used at this point. A method or function may not return the address of this local value. in Visual Studio. Type outref<T> still does not seem to be available either. Am I missing something?
I also tried to drop the pointer parameter, and just return pool.GetReference to only get a different error message.
Addition: the ultimate goal is to be able to do
let aref = Ref pool ptr
let bref = Ref pool ptr
aref <- 42
assert(aref = bref)
e.g. give caller a direct reference to an internal memory, usually backed by an array, similar to Span<T>. I am making this for performance reasons, so it is not OK to allocate on every call to Ref.
For some reason, reducing generalization helped to get rid of the error:
let Ref<'P, 'T when 'T: struct> (pool: IPool<'P, 'T>) pointer = pool.GetReference pointer
Solution provided by
https://github.com/Microsoft/visualfsharp/issues/5366#issuecomment-407521220
Though it does not explain why the original code does not compile.
I don't think it's standard practice to return a byref type. This type is really meant for method parameters, mostly for C# interop with out or ref parameters. Take a look at this StackOverflow question for a good explanation.
What you can do is change the method on your interface to take a tuple of ITypedPointer<'P,'T> and byref<'T> (usage of byref is not allowed with curried parameters) and return unit instead. Then you can call GetReference like any standard .NET method with an out parameter in C#. That would look something like this:
type ITypedPointer<'P, 'T> = interface end
type IPool<'P, 'T when 'T: struct> =
abstract member GetReference: ITypedPointer<'P, 'T> * byref<'T> -> unit
let Ref<'TPool, 'P, 'T when 'TPool :> IPool<'P, 'T>> (pool: 'TPool) pointer =
let mutable value = Unchecked.defaultof<'T>
pool.GetReference(pointer, &value)
value
In the book, "Swift Programming Language 3.0", it mentioned that types of closure include:
Global functions are closures that have a name and do not capture
any values
Nested function are closures that have a name and can
capture values from their enclosing function
Closure expression are
unnamed closure written in a lightweight syntax that can capture
values from their surrounding context
I was just wondering does a function that exist in class scope count as a closure? One can certainly pass around such function as an argument to other function, but is it a closure?
Yes! Absolutely! Here's an example that uses the lowercased() method of String.
let aClosure: (String) -> () -> String = String.lowercased
let anUpperCasedString = "A B C"
print(anUpperCasedString)
let aLowerCaseString = aClosure(anUpperCasedString)()
print(aLowerCaseString)
You can see that the type of this closure is (String) -> () -> String. This is because String.lowercased is completely unapplied, it has no clue what instance it's operating on.
Calling aClosure(anUpperCasedString) will return a closure that's now () -> String. Baked into it is the instance it'll operate on. Only when you call this new closure with no params (()), will it actually execute the body of lowercased(), operating on the instance you gave it in the previous step, and return you the String result.
As a consequence, this is also valid:
let aLowerCaseString = String.lowercased("QWERTY")()
It just does all the steps above in one inlined step.
This technique is called function currying. This post talks more about this technique (called function currying) as it applies to instance methods in Swift.
I'm attempting to implement the interface IDispatchMessageInspector (of WCF fame) in F#:
open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels
type ServiceInterceptor() as interceptor =
abstract member PreInvoke : byref<Message> -> obj
abstract member PostInvoke : byref<Message> -> obj -> unit
default x.PreInvoke m = null
default x.PostInvoke m s = ()
interface IDispatchMessageInspector with
member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke &reply correlationState
This fails to compile with the following error:
However, if I modify my code to the following (note the change of signature in PostInvoke) everything works:
open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels
type ServiceInterceptor() as interceptor =
abstract member PreInvoke : byref<Message> -> obj
abstract member PostInvoke : byref<Message> * obj -> unit
default x.PreInvoke m = null
default x.PostInvoke (m, s) = ()
interface IDispatchMessageInspector with
member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke(&reply, correlationState)
Is this behaviour expected? And if so could someone explain the reasoning behind it....
The reason is that byref<'T> is not a real type in .NET. F# uses this for representing values that are passed via ref and out parameters, but it is not a normal type that could appear anywhere in your program.
F# restricts the scope in which they can be used - you can only use them for local variables (basically passing around a reference or a pointer) and you can use them as method parameters (where the compiler can then compile it as a method parameter).
With curried methods, the compiler is producing a property that returns a function value and so (under the cover), you get something like a property PostInvoke of type FSharpFunc<T1, FSharpFunc<T2, T3>>. And here, T1 or T2 cannot be byref<T> types, because byref is not a real .NET type. So that's why curried methods cannot have byref parameters.
Another case where you can see this is if you, for example, try to create a list of byref values:
let foo () =
let a : list<byref<int>> = []
a
Here you get:
error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Please unwrap these type signatures to help me understand why this doesn't work.
Then, if you have a solution, that would be great too.
I have this code and the agent.Post command has the signature Observer.Create<'T>(onNext: Action<'T>) : IObserver<'T>
let reservatinoRequestObserver = Observer.Create agent.Post
interface IHttpControllerActivator with
To my knowledge, this means that Observer.Create should take an Action with a single generic parameter and then return an IObserver.
Now the definition of Post is member MailboxProcessor.Post : message:'Msg ->unit
So... Post is a method, no? It is a method that takes a single parameter no? And it returns void no? So shouldn't it be a candidate for Observer.Create? Isn't that the exact specification of Action<'T>?
Well, somethings up, I get This function takes too many arguments, or is used in a context where a function is not expected:
Help me out... I freely admit I suck at F#
First, agent.Post returns unit, which is a different thing from void. F# will usually convert back and forth between void and unit for you, but they are not the same thing.
Second, F# functions do not implicitly convert to .NET delegates.
But there are some ways to do it:
You can explicitly create the delegate using its constructor:
let o = Observer.Create (new Action<_>( agent.Post ))
Lambdas are nicely wrapped too
let o = Observer.Create (fun msg -> agent.Post msg)
Use F# Rx-wrappers
Also there are a couple of F# wrappers/interop for Rx on nuget - just have a look, I think any will do