What does the :> operator do in F#? - f#

What does the :> operator do in F#?
e.g.
myFunction x :> System.Object

It converts a type to type that is higher in the hierarchy. So it's a conversion operator.
See the following example (take from here and the previous definition too) :
type Base1() =
abstract member F : unit -> unit
default u.F() =
printfn "F Base1"
type Derived1() =
inherit Base1()
override u.F() =
printfn "F Derived1"
let d1 : Derived1 = Derived1()
// Upcast to Base1.
let base1 = d1 :> Base1

Converts a type to type that is higher in the hierarchy.
Source: https://msdn.microsoft.com/en-us/library/dd233228.aspx
--
Like casting an Entity type to Player type.

Related

type inference on abstract type with a tuple

Based on this kvb's answer, this code compiles (F#4) and runs :
type Untupler = abstract Apply : 'u * 'u -> 'u
let myotherFun arg1 arg2 =
printfn "myotherFun result is : %A %A" arg1 arg2
let myFunction tup1 tup2 (i:Untupler) =
myotherFun (i.Apply tup1) (i.Apply tup2)
let reskvb = myFunction (1,2) ("Hello","World") { new Untupler with member __.Apply (x,y) = snd (x,y) }
But if the last line is replaced by the initial answer :
let reskvb = myFunction (1,2) ("Hello","World") { new Untupler with member __.Apply x = fst x }
then the compiler complains with error FS0768 :
The member 'Apply' does not accept the correct number of arguments, 2 arguments are expected
I do not understand why the compiler seems to fail to infer that x is indeed a tuple. Or is there another issue I am missing ? Thx.
The reason for this is that when you start using interfaces, you move into F#'s support for Object-Oriented Programming, and in F#, all OOP interop methods are tupled by default.
Thus, the Apply method is interpreted as being a method that takes two method arguments, rather than a function that takes a single tuple as input.

Generic type constrained on f# method involving static type conversion

I'm trying to create a function in FSharp that will take a parameter of an interface type and a parameter of a derived type, which passes on both parameters as implementations of that interface:
Simplified example:
type IFoo =
abstract member Compare : IFoo -> bool
type Foo =
interface IFoo with
member this.Compare _ = false
let doCompare (a : IFoo) (b : IFoo) = a.Compare(b)
let comp (x : IFoo) (y : #IFoo) = doCompare x (y :> IFoo)
let comp2 (x : 'T) (y : #'T) = doCompare x (y :> 'T)
I'm getting the following two errors on the generic version (here, comp2):
On the parameter:
This construct causes code to be less generic than indicated by its type annotations.
The type variable implied by the use of a '#', '_' or other type annotation at or near '...'
has been constrained to be type ''T'.
On the cast operator:
The static coercion from type 'T to 'T involves an indeterminate type based on information prior to this program point.
Static coercions are not allowed on some types. Further type annotations are needed.
Is there a way I can fix this, other than creating a signature using 'T 'U and casting via object which is obviously unsafe ?
This code (together with the original code that showed this problem - which is for wrapping NSubstitute in a test fixture) is available on tryfsharp
The # is syntactic sugar for a subtype constraint, ie. comp2 is equivalent to:
let comp2<'T, 'U when 'U :> 'T> (x:'T) (y:'U) = doCompare x (y :> 'T)
Unfortunately, the 'U :> 'T part is not supported by the type system (you cannot constrain a type to be a subtype of a type variable), so this is not possible.

IEnumerable and array comprehension

I wonder why the second line reports a compiler error
the type Relations is not compatible with seq<'a>
while the first infers a type Relation for r.
type Microsoft.Office.Interop.Access.Dao.Database with
member x.f() =
let relations = [for r in x.Relations -> r]
let relations2 = x.Relations |> Seq.map id
()
What precise property makes it possible to loop over Relations using for?
// Edit reproduction step :
I create a blank solution in VS2012, add a reference to Microsoft.Office.Interop.Access.Dao, and paste the code below.
module toto =
type Class1() =
member this.X = "F#"
type Microsoft.Office.Interop.Access.Dao.Database with
member x.f() =
let relations = [for r in x.Relations -> r]
let relations2 = x.Relations |> Seq.map id
()
r is typed as Relation, and not obj
This doesn't entirely mesh with what you've said, but one scenario in which a sequence expression would work but not Seq.map is when a type implements System.Collections.IEnumerable but not System.Collections.Generic.IEnumerable<'T> (aka seq<'T>). For example, in this code t is inferred as obj list, but the next line doesn't compile.
type T() =
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (Seq.init 10 id).GetEnumerator() :> _
let t = [for x in T() -> x]
let t2 = T() |> Seq.map id //ERROR: The type 'T' is not compatible with the type 'seq<'a>'
This scenario is especially common for libraries created prior to .NET 2.0.

How to define and use % as a prefix operator?

type T() =
static member (~%)(t : T) = t
let t = T()
let t' = %t // FAILS
The error message says t was expected to be of type Quotation.Expr<'a>.
% is a supposedly valid prefix operator, but is it possible to actually use it?
The reason why you are seeing this behavior is because F# does not define (~%) with static constraints like most top-level operators. It is defined as a function Quotations.Expr<'a> -> 'a. Hence, the (~%) function (which is an alias for op_Splice) you defined on type T is not resolved by uses of the top-level (~%) operator.
You can see this by the following FSI interaction:
> <# (~%) #>;;
<# (~%) #>;;
^^^^^^^^^^
C:\Users\Stephen\AppData\Local\Temp\stdin(5,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : Expr<(Expr<'_a> -> '_a)>
Either define 'it' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
Thus if we redefine the top-level (~%) operator as follows, then your example will compile without error:
let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x))
but do note that quotation splicing will no longer work:
let x = <# 3 #>
<# %x #>
----^
error FS0001: The type 'Expr<int>' does not support the operator '~%'
that's because the original definition of (~%) is treated specially by the compiler for quotation splicing. Indeed, you can see in the Expr and Expr<'T> signatures that those types do not define any operators at all, let alone op_Splice.
You can see similar results with && and || infix operators. Which can be redefined (mapping to op_BooleanAnd and op_BooleanOr), but unless they are, they are treated specially by the compiler.
I'm not exactly sure why the % operator behaves like this, but you can redefine it using global let binding:
let (~%) a = -a
%10
If the operator cannot be defined as static member (I'm not sure if that's the case, or if I'm just missing something), you can still define an inline definition that invokes some static member of an object. This should give you essentially the same functionality:
// Instead of defining static member '%', we define static member 'Percent'
type T() =
static member Percent(t : T) = t
// Inline definition of '~%' that calls the static member 'Percent' of an object
let inline (~%) (x : ^T) = (^T : (static member Percent : ^T -> 'R) (x))
// Now you can use the '%t' syntax to invoke the static member
let t = T()
let t' = %t
Background: In F# quotation code, it is used for "splicing" of expressions into another expression (to build an expression that is composed from another, previously defined expression). The error message suggests that the compiler did not see your definition.
let two = <# 2 #>
let oneAndTwo = <# 1 + %two #>

How to declare a generic function returning a type satisfying multiple constraints in F#?

What I am trying to write:
type A() =
interface IX with ...
interface IY with ...
type B() =
interface IX with ...
interface IY with ...
let mk t : 'T when 'T :> IX and 'T :> IY =
match t with
| Choice1 -> new A()
| Choice2 -> new B()
Note the type constraints on the return type of mk. It does not compile though, the compiler complains that it can't convert A and B to 'T.
The constraint is okay, but the problem is that there is no type that would satisfy the constraint and that would be a supertype of both A and B.
The match construct needs to return the same type from both of the branches, so you'd need to add upcast (:>) to some type such that the conversion works for both of the branches. The type could be either IX or IY, but that wouldn't satisfy the constraint.
This would be possible only if .NET allowed you to write something like IX+IY which would mean a type that implements both of the interfaces. Then you would also be able to work with values of this type e.g.:
let (a:IX+IY) = new A() // This isn't supported
I think that the best solution is to simply return a tuple IX * IY containing two times the same instance, but represented as different type. Here the constriant you wrote can be quite useful:
// Type: 'a -> IX * IY when 'a :> IX and 'a :> IY
let asTuple a = (a :> IX, a :> IY)
let mk t =
match t with
| Choice1Of2() -> new A() |> asTuple
| Choice2Of2() -> new B() |> asTuple
If you control types A and B, then the simplest solution would be to define
type IXY =
inherit IX
inherit IY
and then have A and B inherit IXY, and mk would just return an IXY rather than a generic type (which doesn't really make sense anyway, even without the constraints).

Resources