Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upcasting in F# with sequences

Tags:

f#

I'm trying to work with expressions in F# (the System.Linq.Expression kind). Here is a quick example of the problem I am having:

let blah = seq {
    yield Expression.New(typedefof<'T>)
    yield Expression.Constant(1)
}

What I would like is for blah to be a seq<Expression>. However the sequence infers its type by the first yield, which is a NewExpression. This will cause the second yield to result in a compilation failure because it is a ConstantExpression. A working solution is to upcast all of the yields:

let blah = seq<Expression> {
    yield Expression.New(typedefof<'T>) :> Expression
    //or
    yield upcast Expression.Constant(1)
}

But that feels unwieldy, having to upcast every single time. I thought flexible types might be a possible solution as well, but I've had trouble with that as well. seq<#Expression> doesn't seem to work.

Is there a way I can generate a sequence of expressions without having to upcast every single one of them?

like image 783
vcsjones Avatar asked Nov 19 '13 14:11

vcsjones


1 Answers

As others already mentioned, F# does not usually automatically insert upcasts in your code, so you'll need to add a type annotation and cast or the upcast keyword - I think the comments already cover all the options.

There are two cases when the compiler does upcasts - one is when passing argument to a function and the other is when you create an array or a list literal. The second can actually be used to simplify your example:

let blah<'T> : Expression list = 
  [ Expression.New(typedefof<'T>) 
    Expression.Constant(1) ]

Here, the compiler inserts upcast to Expression automatically. I suppose your actual use case is more complicated - when you need sequence expressions with yield, this will not work because then you're writing sequence expresions rather than list literals

like image 109
Tomas Petricek Avatar answered Oct 13 '22 05:10

Tomas Petricek