F# Generics not so generic

178 views Asked by At

I've come up against this a couple of times, but I'm really at a loss as to why it happens.

I've got a discriminated union like:

type MStep<'A, 'B> =
| Shuttle of Quotations.Expr<'B> * Quotations.Expr<'B>

There's more to the union, but this shows the basic problem.

If I do:

let s1 = Shuttle(<@ l.SomeIntProp @>, <@ r.SomeIntProp @>)
let s2 = Shuttle(<@ l.SomeStrProp @>, <@ r.SomeStrProp @>)

I get a compiler error:

This expression was expected to have type int, but here has type string

Likewise, if I create them in the other order (string then int), I get the same error but the other way around.

I can see that the compiler is likely inferring 'B based on my usage, but what if I want 'B to be truly generic?


As requested here is a more complete example:

type MStep<'A, 'B> =
    | Shuttle of Quotations.Expr<'B> * Quotations.Expr<'B>
    | Ident of Quotations.Expr<'B>
    | Trans of Quotations.Expr<'A> * Quotations.Expr<'B> * ('A -> 'B)

let doMig (f:Table<'A>, t:Table<'B>, s:('A * 'B -> MStep<'C, 'D> list)) =
    ignore()

let a = doMig(bpdb.Adjustments, ndb.Adjustments, (fun (l,r) ->
    [
        Shuttle(<@ l.Id @>, <@ r.Id @>)
        Shuttle(<@ l.Name @>, <@ r.Name @>)
    ]
    ))

This produces the compiler error as seen above.

NOTE:

bpdb and ndb are both database contexts provided by the SqlDataConnection type provider.

The open namespaces are:

open System
open System.Data
open System.Data.Linq
open Microsoft.FSharp.Data.TypeProviders
open Microsoft.FSharp.Linq
open System.Xml
open System.Xml.Linq
open Microsoft.FSharp.Quotations.Patterns
open System.Reflection
open System.Diagnostics
1

There are 1 answers

3
John Palmer On BEST ANSWER

The problem is obvious here:

let t = [ //inserted t to have a concrete variable
    Shuttle(<@ l.Id @>, <@ r.Id @>); 
    Shuttle(<@ l.Name @>, <@ r.Name @>)
]

What exactly is the type of t. The first element gives MStep<_,int> list and the second gives MStep<_,string> which are different.

You can only put elements that are the same type into a list.