Why is Type Annotation Required Here? - f#

This function has the signature: (UnionCaseInfo -> bool) -> 'T option
let private findCase<'T> f =
match FSharpType.GetUnionCases typeof<'T> |> Array.filter f with
|[|case|] -> Some (FSharpValue.MakeUnion(case,[||]) :?> 'T)
|_ -> None
This function, which calls the above function, has the signature: int -> obj
let CreateFromId<'T> id =
match findCase (fun case -> case.Tag = id) with
| Some c -> c
| None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id)
In the pattern for CreateFromId, intellisense shows that c is inferred to be of type obj, even though it shows the correct signature for findCase. Why does the type seem to have been "lost" in the pattern?
(I can workaround this by specifying the return type of CreateFromId to 'T)

Because the type parameter 'T is not referenced in the body of the function, so type inference has no way to know your intention was to name 'T the return type.
So you can either add it in the body as the return type (as you already figured it out) or remove it from the declaration:
let CreateFromId id = ...
By removing it works because F# does automatic generalization, the only different is it will use an arbitrary name for the type variable, but even if you want to name that type variable 'T what I would do is add it as a return type but no in the declaration between brackets:
let CreateFromId id : 'T = ...

The type of CreateFromId was inferred to by int -> obj because there's nothing "linking" the two 'T type arguments on your functions.
findCase is properly generic over 'T, but CreateFromId is only declared to be generic, and the generic type argument is never used.
Annotating the function with the desired type is good enough to make the types line up. You can also call findCase explicitly providing the type:
let CreateFromId<'T> id =
match findCase<'T> (fun case -> case.Tag = id) with
| Some c -> c
| None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id)
Or as the other answer suggests, just drop the 'T from CreateFromId and let type inference do its thing.

Related

Deconstructing Discriminated Unions

I have a discriminated-union type of the form
type ParameterName = string
type ParameterValues =
| String of string[]
| Float of float[]
| Int of int[]
type Parameter = Parameter of ParameterName * ParameterValues
I want to pass the ParameterValues part to a function taking generic arguments returning unit, such as
let func1 (name:string) (data:'a) = printfn "%s" name
To deconstruct Parameter I could wrap func1 like this
let func2 (Parameter (name, values)) =
match values with
| String s -> func1 name s
| Float s -> func1 name s
| Int s -> func1 name s
however this is inconvenient if I have to do this for multiple functions. Instead, I would like to define a more flexible wrapper like this:
let func3 (fn: ('a -> 'b -> unit)) (Parameter (name, values)) =
match values with
| String s -> fn name s
| Float s -> fn name s
| Int s -> fn name s
This however fails, as the type of b gets restricted to string[] in the first option of the match expression; consequently the match expression fails with the error Type string does not match type float.
Is this expected? How can I work around this problem?
This is an expected behaviour. The problem is that you cannot directly pass a generic function as an argument to another function in F#. When you define a function as follows:
let func3 (fn: ('a -> 'b -> unit)) (Parameter (name, values)) = (...)
... you are defining a generic function func3 that has two generic parameters and, when those are specified, can be called with a given function and a parameter. This can be written as:
\forall 'a, 'b . (('a -> 'b -> unit) -> Parameter -> unit)
What you would need to do is to make those type parameters not top-level, but make the first parameter itself a generic function. You could write this as:
(\forall 'a, 'b . ('a -> 'b -> unit)) -> Parameter -> unit
This can be clumsily written in F# using interfaces:
type IFunction<'a> =
abstract Invoke<'b> : 'a -> 'b -> unit
let func1 =
{ new IFunction<string> with
member x.Invoke<'b> name (data:'b) = printfn "%s" name }
let func3 (fn: IFunction<string>) (Parameter (name, values)) =
match values with
| String s -> fn.Invoke name s
| Float s -> fn.Invoke name s
| Int s -> fn.Invoke name s
In practice, your function does not really need to be generic, because you are never using the second argument - but you could probably achieve pretty much anything that you can achieve with this interfaces trick just by passing the data as obj and your code would be significantly simpler than this monstrosity!
Following the suggestions by Lee and Tomas, I came up with the following solution:
type Parameter = Parameter of string * obj
let func0 (name:string) (data:obj) = printfn "%s %A" name data
let func1 (fn: string->obj->unit) (Parameter (name, value)) =
fn name value
let p1 = Parameter ("p1", [|"a"; "b"|])
let p2 = Parameter ("p1", [|1.; 2.|])
func1 func0 p1
func1 func0 p2

Where to add type annotations to curried functions?

In F# interactive, I can find the type of sprintf.
>sprintf;;
val it : (Printf.StringFormat<'a> -> 'a) = <fun:clo#163>
I can find the type of sprintf curried with the first parameter, if the curried function is not generic.
> sprintf "%g";;
val it : (float -> string) = <fun:it#134-16>
But if it is generic, then I get the value restriction error.
> sprintf "%A";;
error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : ('_a -> string)
Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, add a type annotation.
I can add a type annotation to get rid of the value restriction like this, specializing the function for a type, eg. DateTime.
>let f : (DateTime -> string) = sprintf "%A";;
val f : (DateTime -> string)
How can I add the type annotation without the binding? I've tried the following ...
>sprintf "%A" : (DateTime -> string);;
error FS0010: Unexpected symbol ':' in interaction. Expected incomplete structured construct at or before this point, ';', ';;' or other token.
This is a similar example but harder ...
>sprintf "%a";;
error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : ((unit -> '_a -> string) -> '_a -> string)
Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, add a type annotation.
You just need to enclose your expression in parenthesis:
open System;;
(sprintf "%A" : DateTime -> string);;
val it : (DateTime -> string) = <fun:it#2>
That way you can specify the type annotation without the binding.
What is actually happening is that fsi binds the last thing you type to a variable called it. It effectively does
let it = sprintf "%a";;
Type annotations would need to go on the left hand side of the = which you can't access. The problem is that you need a concrete type to give to any variable (in this case it). A workaround could be
(fun t:DateTime -> sprintf "%a" t)

In F#, How can I cast a function to a different delegate?

I need to cast a function with the signature Thing -> Thing -> int to a Comparison<Thing>.
For example, when I have:
Array.Sort(values, mySort)
I get an error stating "This expression was expected to have type Comparison but here has type Thing -> Thing -> int"
When I try this:
Array.Sort(values, (fun (a, b) -> mySort a b))
(actually, this is by way of a wrapper object)
I get an error stating "Type constraint mismatch. The type ''a -> 'b' is not compatible with the type 'Comparison'"
How am I supposed to provide a Comparison<T>?
FYI: Comparison<T> is a delegate with the signature 'T * 'T -> int
This works for me:
let values = [|1;2;3|]
let mySort a b = 0
Array.Sort(values, mySort)
But have you tried:
Array.Sort(values, Comparison(mySort))
Oddly, despite the fact that delegate signatures are expressed in tupled form (e.g. 'T * 'T -> int), you need to provide your function in curried form (e.g. fun a b -> mySort a b). See section 6.4.2 of the spec.

How to downcast from obj to option<obj>?

I have a function that takes a parameter of type object and needs to downcast it to an option<obj>.
member s.Bind(x : obj, rest) =
let x = x :?> Option<obj>
If I pass (for example) an Option<string> as x, the last line throws the exception: Unable to cast object of type 'Microsoft.FSharp.Core.FSharpOption'1[System.String]' to type 'Microsoft.FSharp.Core.FSharpOption'1[System.Object]'.
Or, if I try a type test:
member s.Bind(x : obj, rest) =
match x with
| :? option<obj> as x1 -> ... // Do stuff with x1
| _ -> failwith "Invalid type"
then x never matches option<obj>.
In order to make this work, I currently have to specify the type the option contains (e.g. if the function is passed an option<string>, and I downcast the parameter to that rather than option<obj>, the function works.
Is there a way I can downcast the parameter to option<obj> without specifying what type the option contains? I've tried option<_>, option<#obj>, and option<'a> with the same results.
By way of background, the parameter needs to be of type obj because I'm writing an interface for a monad, so Bind needs to bind values of different types depending on the monad that implements the interface. This particular monad is a continuation monad, so it just wants to make sure the parameter is Some(x) and not None, then pass x on to rest. (The reason I need the interface is because I'm writing a monad transformer and I need a way to tell it that its parameter monads implement bind and return.)
Update: I managed to get around this by upcasting the contents of the option before it becomes a parameter to this function, but I'm still curious to know if I can type-test or cast an object (or generic parameter) to an option without worrying about what type the option contains (assuming of course the cast is valid, i.e. the object really is an option).
There isn't any nice way to solve this problem currently.
The issue is that you'd need to introduce a new generic type parameter in the pattern matching (when matching against option<'a>), but F# only allows you to define generic type parameters in function declarations. So, your only solution is to use some Reflection tricks. For example, you can define an active pattern that hides this:
let (|SomeObj|_|) =
let ty = typedefof<option<_>>
fun (a:obj) ->
let aty = a.GetType()
let v = aty.GetProperty("Value")
if aty.IsGenericType && aty.GetGenericTypeDefinition() = ty then
if a = null then None
else Some(v.GetValue(a, [| |]))
else None
This will give you None or Some containing obj for any option type:
let bind (x : obj) rest =
match x with
| SomeObj(x1) -> rest x1
| _ -> failwith "Invalid type"
bind(Some 1) (fun n -> 10 * (n :?> int))
I am not certain why you need to get your input as obj, but if your input is an Option<_>, then it is easy:
member t.Bind (x : 'a option, rest : obj option -> 'b) =
let x = // val x : obj option
x
|> Option.bind (box >> Some)
rest x
To answer your last question: you can use a slight variation of Tomas' code if you need a general-purpose way to check for options without boxing values beforehand:
let (|Option|_|) value =
if obj.ReferenceEquals(value, null) then None
else
let typ = value.GetType()
if typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<option<_>> then
let opt : option<_> = (box >> unbox) value
Some opt.Value
else None
//val ( |Option|_| ) : 'a -> 'b option
let getValue = function
| Option x -> x
| _ -> failwith "Not an option"
let a1 : int = getValue (Some 42)
let a2 : string = getValue (Some "foo")
let a3 : string = getValue (Some 42) //InvalidCastException
let a4 : int = getValue 42 //Failure("Not an option")

F# return type coercion

In F# I have a function that returns System.Linq.Expression instances:
and System.Object with
member this.ToExpression() =
match this with
| :? System.Int32 -> Expression.Constant(this) :> Expression
| :? System.Boolean -> Expression.Constant(this) :> Expression
| :? Tml.Runtime.Seq as s -> s.ToExpression()
| _ -> failwith "bad expression"
If I omit the type coercions on the return values F# will infer the return type of the function to ConstantExpression. My first thought was to explicitly mark the return type as being : #Expression, but that didn't work. Is there a more elegant way of doing this that doesn't involve manually casting return types to the most generic type?
Thanks.
Edit: Thanks to all of you for the answers. I'll go with the explicit return type + upcast scenario.
Here are a couple ways you might prefer:
open System.Linq.Expressions
type System.Object with
member this.ToExpression() : Expression = // explicit
match this with
| :? System.Int32 -> upcast Expression.Constant(this) // upcast
| :? System.Boolean -> Expression.Constant(this) :> _ // _
| _ -> failwith "bad expression"
By explicitly stating the return type on the member declaration, you can then infer it in the body, e.g. via _ as a "please infer this type for me" or by using the upcast operator which will infer the type to up-cast to from the constraints.
I don't think there is any significantly more elegant way of writing this, unfrotunately.
The compiler requires that all branches of the match expression will have the same return type and it doesn't implicitly insert any coercions. You can use the upcast keyword to insert a coercion without specifying the target type - in this case, the compiler will use other information (such as type annotations) to determine the type and you won't have to repeat the type:
and System.Object with
member this.ToExpression() : Expression =
match this with
| :? System.Int32 -> upcast Expression.Constant(this)
| :? System.Boolean -> upcast Expression.Constant(this)
| :? Tml.Runtime.Seq as s -> upcast s.ToExpression()
| _ -> failwith "bad expression"
I added type annotation and upcast to each of the expression and type annotation, so the F# compiler infers that the upcast needs to coerce the result to Expression. The only place where the compiler inserts implicit coercions is when calling a function, so you could also write the following (but I'm not sure if it's any better):
// Thanks to implicit coercions, we don't even need #type
let expr (a:Expression) = a
// and then for example:
| :? System.Int32 -> Expression.Constant(this) |> expr
For some reason, upcast is a keyword, so you cannot use it with pipelining, so definining a function like this may have some benefits.
Strictly speaking this is not removing the coersion but in my opinion it's a bit better on the eye (and will save you a little bit of typing too :) )
open System.Linq.Expressions
let Constant obj = Expression.Constant(obj) :> Expression
type System.Object with
member this.ToExpression()
match this with
| :? System.Int32 -> Constant(this)
| :? System.Boolean -> Constant(this)
| _ -> failwith "bad expression"
since the type of Constant is a'->Expression it will work in both cases. The down side is of cause that you will have to define a function for each of the Expression factory methods you are going to use.

Resources