Please explain the following function signature which appeared when I hovered over the function in VS Code. I'm especially curious what exactly "requires" means and why 'b is 'a.
val handleSingleEvent:
: Request
-> 'b (requires :> seq<list<string>>)
Generic Parameters
'b is 'a
Below is the code
let handleEvents (requests: Request list, reqEventQueue: EventQueue, session: Session) =
let rec handleSingleEvent (request: Request) : seq<list<string>> =
seq {
let eventObj = reqEventQueue.NextEvent()
match eventObj.Type with
| Event.EventType.REQUEST_STATUS -> yield processMiscEvents eventObj |> makeJson
| Event.EventType.ADMIN -> yield processAdminEvent eventObj |> makeJson
| Event.EventType.AUTHORIZATION_STATUS -> yield processAuthEvent eventObj session |> makeJson
| Event.EventType.PARTIAL_RESPONSE ->
yield processReferenceResponseEvent eventObj
|> makeJson
yield! handleSingleEvent request
| Event.EventType.RESPONSE -> yield processReferenceResponseEvent eventObj |> makeJson
| _ -> yield processMiscEvents eventObj |> makeJson
} |> ignore
handleSingleEvent request
List.map (fun request -> handleSingleEvent request) requests
After adding the return type annotation seq<list<string>>, hovering over the function in VS Code now displays the function signature as
val handleSingleEvent:
: Request
-> seq<list<string>>
"requires" disappeared and "Generic Parameters `b is `a" disappeared.
'requires' indicates a member constraint, meaning that the generic type argument is constrained to exhibit such member. As a brief example:
let inline f<'b when 'b : (member Name : string)> (x: 'b) = x
The generic type 'b is now constrained to have a member Name that returns a string.
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/generics/constraints
Related
What does a # before a type name mean in F#?
For example here:
let getTestData (inner : int [] -> #seq<int>) (outer : #seq<int> [] -> #seq<'U>) =
(testData |> Array.map inner) |> outer
The syntax #type is called a "flexible type" and it is a shortcut for saying that the type can be any type that implements the given interface. This is useful in cases where the user of a function may want to specify a concrete type (like an array or a list).
For a very simple example, let's look at this:
let printAll (f: unit -> seq<int>) =
for v in f () do printfn "%d" v
The caller has to call printAll with a lambda that returns a sequence:
printAll (fun () -> [1; 2; 3]) // Type error
printAll (fun () -> [1; 2; 3] :> seq<int>) // Works, but tedious to write!
If you use flexible type, the return type of the function can be any implementation of seq<int>:
let printAll (f: unit -> #seq<int>) =
for v in f () do printfn "%d" v
printAll (fun () -> [1; 2; 3]) // No problem!
In reality, the syntax #typ is just a shortcut for saying 'T when 'T :> typ, so you can rewrite the function in my example as:
let printAll<'T when 'T :> seq<int>> (f: unit -> 'T) =
for v in f () do printfn "%d" v
I have the function to map a function to "Reader-Result", where f is 'a->'b:
('a->'b) -> Reader<Result<'a,'c>> -> Reader<Result<'b,'c>>
let map f = Reader.map <| Result.map f
But how to I write a similar map that takes the function 'a->Result<'b,'c> as input?
The function that's analogous to map, but whose argument returns a Result<_,_>, is called bind. Its signature is:
bind : ('a -> Result<'b, 'c>) -> Result<'a, 'c> -> Result<'b, 'c>
I am assuming that the signature you want is:
yourFunction : ('a -> Result<'b, 'c>) -> Reader<Result<'a, 'c>> -> Reader<Result<'b, 'c>>
To obtain such function, combine Result.bind with Reader.map:
yourFunction f = Reader.map <| Result.bind f
TL;DR: How do I get the actual property value from a quotation of the form
<# myInstance.myProperty #>
I'm trying to simplify INotifyPropertyChanged using F#. Instead of subscribing directly to PropertyChanged, I want to use a method that takes a code quotation containing the property I want to subscribe to (e.g. <# vm.IsChanged #>) and a callback (or alternatively just the quotation and returns an observable of the relevant property). For example:
type MyVm() =
inherit INPCBaseWithObserveMethod()
...
let vm = new MyVm()
vm.Observe <# vm.IsChanged #> (fun isChanged -> ...)
I'm new to code quotations and I'm struggling with the implementation of the Observe method. I know how to get the property name from this kind of expression, but not the value. Here's what I have so far (note the placeholder in propInfo.GetValue):
type ViewModelBase() =
// Start INPC boilerplate
let propertyChanged = new Event<_, _>()
interface INotifyPropertyChanged with
[<CLIEvent>]
member __.PropertyChanged = propertyChanged.Publish
member this.OnPropertyChanged(propertyName : string) =
propertyChanged.Trigger(this, new PropertyChangedEventArgs(propertyName))
// End INPC boilerplate
member this.Observe (query: Expr<'a>) (callback: 'a -> unit) : unit =
match query with
| PropertyGet(instanceExpr, propInfo, _) ->
(this :> INotifyPropertyChanged).PropertyChanged
|> Observable.filter (fun args -> args.PropertyName = propInfo.Name)
|> Observable.map (fun _ -> propInfo.GetValue(TODO) :?> 'a)
|> Observable.add callback
| _ -> failwith "Expression must be a non-static property getter"
I figured it out based on some experimentation and this quotation eval function. In the most simple case (when vm in <# vm.MyProperty #> is a local let-bound value), the instance expression will match the Value pattern:
| PropertyGet(Some (Value (instance, _)), propInfo, [])
instance can then be passed to PropertyInfo.GetValue. However, if vm is a field (class-level let binding) or anything else, then the pattern will be different (e.g. containing a nested FieldGet which will need to be evaluated to get the correct instance you can pass to PropertyInfo.GetValue).
In short, it seems the best course of action is simply using the eval function I linked to. The whole ViewModelBase class then becomes (see this snippet for a more complete implementation):
type ViewModelBase() =
/// Evaluates an expression. From http://www.fssnip.net/h1
let rec eval = function
| Value (v, _) -> v
| Coerce (e, _) -> eval e
| NewObject (ci, args) -> ci.Invoke (evalAll args)
| NewArray (t, args) ->
let array = Array.CreateInstance (t, args.Length)
args |> List.iteri (fun i arg -> array.SetValue (eval arg, i))
box array
| NewUnionCase (case, args) -> FSharpValue.MakeUnion (case, evalAll args)
| NewRecord (t, args) -> FSharpValue.MakeRecord (t, evalAll args)
| NewTuple args ->
let t = FSharpType.MakeTupleType [| for arg in args -> arg.Type |]
FSharpValue.MakeTuple (evalAll args, t)
| FieldGet (Some (Value (v, _)), fi) -> fi.GetValue v
| PropertyGet (None, pi, args) -> pi.GetValue (null, evalAll args)
| PropertyGet (Some x, pi, args) -> pi.GetValue (eval x, evalAll args)
| Call (None, mi, args) -> mi.Invoke (null, evalAll args)
| Call (Some x, mi, args) -> mi.Invoke (eval x, evalAll args)
| x -> raise <| NotSupportedException(string x)
and evalAll args = [| for arg in args -> eval arg |]
let propertyChanged = new Event<_,_>()
interface INotifyPropertyChanged with
[<CLIEvent>]
member __.PropertyChanged = propertyChanged.Publish
member this.OnPropertyChanged(propertyName : string) =
propertyChanged.Trigger(this, new PropertyChangedEventArgs(propertyName))
/// Given a property-getter quotation, calls the callback with the value of
/// the expression every time INotifyPropertyChanged is raised for this property.
member this.Observe (expr: Expr<'a>) (callback: 'a -> unit) : unit =
match expr with
| PropertyGet (_, propInfo, _) ->
(this :> INotifyPropertyChanged).PropertyChanged
|> Observable.filter (fun args -> args.PropertyName = propInfo.Name)
|> Observable.map (fun _ -> eval expr :?> 'a)
|> Observable.add callback
| _ -> failwith "Expression must be a property getter"
Observe can of course be trivially modified to return an observable instead of subscribing directly.
Note that in many scenarios Observable.DistinctUntilChanged might be desired after Observable.map. (I use Observe to, among other things, trigger animations from view model properties, and due assumptions in my particular animation code, the animations got all wonky when there were several subsequent calls to the callback with an unchanged property value.)
Given a DU like
type Result<'a, 'b> = Ok of 'a | Error of 'b
and some functions
let doA () = Ok true
let doB () = Error <| exn "Fail"
let doC = function | 1 -> Ok "one" | x -> Error x
How do you define a function to cast the value?
toObjResult : x:obj -> Result<obj, obj> //where x is guaranteed to be Result<'a,'b>
Usage
let data =
[ doA() |> box
doB() |> box
docC 1 |> box
docC 2 |> box ]
|> List.map toObjResult
All attempts so far restrict the types of 'a and 'b to be obj
let toObjResult (x:obj) =
match x with
| :? Result<'a, 'b> as r ->
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
| _ -> Error <| (exn "Invalid type" |> box)
resulting in errors like
System.InvalidCastException: Unable to cast object of type 'Ok[System.Boolean,System.Object]' to type 'Result`2[System.Object,System.Object]'.
There is no way to do this without using reflection, enumerating all types, or modifying the type.
Using reflection can be slow, but lets you do what you want (see [the GenericType active pattern from this answer) and the answer from #robkuz shows how you can do this by listing all the cases that you want to cover - the problem is that this does not scale well.
Finally, if you were happy to modify your Result<'a, 'b> type, you could add a non-generic interface that lets you get the value as a boxed value:
type IBoxedResult =
abstract Boxed : Result<obj, obj>
and Result<'a, 'b> =
| Ok of 'a
| Error of 'b
interface IBoxedResult with
member x.Boxed =
match x with
| Ok v -> Ok (box v)
| Error v -> Error (box v)
Now you can cast obj to IBoxedResult and use Boxed to get the value as Reslt<obj, obj>:
[ box (Ok true)
box (Ok 1) ]
|> List.map (fun o -> (o :?> IBoxedResult).Boxed)
You have to match on the exact generic type params of your Result type in your matching expression
let matchR r =
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
let toObjResult (x:obj) =
match x with
| :? Result<bool, _> as r -> matchR r
| :? Result<string, int> as r -> matchR r
| :? Result<_, Exception> as r -> matchR r
| _ -> Error (box "Invalid type" )
sadly you can't match on unrealised type params (which is really bad)
I found similar things, but not exactly what i'm looking for
Why does
let map x f = f x
return
val map : 'a -> ('a -> 'b) -> 'b
and
let rec merge f xs a =
match xs with
| [] -> a
| y::ys -> f y (merge f ys a);;
return
val merge : f:('a -> 'b -> 'b) -> xs:'a list -> a:'b -> 'b
and
let rec merge2 a = function
| [] -> a
| x::xs -> fold f (f a x) xs;;
returns
val merge2: f:('a -> 'b -> 'a) -> a:'a -> _arg1:'b list -> 'a
Thank you for the clarification.
Ok I'll show you the first one then you can check the others.
Notice how you do f x this means that f is a function (that always has signature 'a -> 'b for some 'a and 'b.
Now as x is the argument to f it must have the same type as the input to f which I named 'a here.
Now the result of f x is of course of type 'b
Now put it all together:
map takes two arguments:
x : 'a
and f : 'a -> 'b
and has result-type 'b
so it has signature map : 'a -> ('a -> 'b) ->b`
Here is the same argument for your
let rec merge f xs a =
match xs with
| [] -> a
| y::ys -> f y (merge f ys a);;
first look at the first case of the match:
it matches an empty list so xs much be a list of some type 'a: xs : 'a list
it returns a which has some unknown type 'b which is also the result of the match and therefore merge itself!
now to the second line:
As xs had type 'a list now you must have
y : 'a
ys : 'a list
therefore you plug in a 'a and then a 'b into f and return it's result to the match and merge (which, as we have seen, has return-type 'b)
You now see, that f must have type f : 'a -> 'b -> 'b and you are again done if you assemble the type of merge
side-note
remember how I claimed that every function has signature 'a -> 'b for some types and now I write stuff like 'a -> 'b -> 'b?
This is indeed consistent if you read the last as 'a -> ('b -> 'b) which is of course just what we call currying: you don't need functions with multiple arguments if you can just return functions and as long as you don't look to deep into the produced IL you should think of F# doing exactly this ;)
I think you will manage the last one yourself - try it, if you have problems edit your question to indicate your problem and we gonna help ;)