F# 从查询表达式转换类型

F# casting type from query expression

我有以下形式的查询表达式:

let result = query { for row in context.Table do
                     where (row.id = 111111)
                     select (row.col1,row.col2,row.col3) }

结果return是一个 IQueryable*Nullable*Nullable> 类型的值。我想要它 return seq*seq*seq.

我可以尝试这样修改它:

let result :seq<float>*seq<float>*seq<float> = query { for row in context.Table do
                                               where (row.id = 111111)
                                               select (row.col1,row.col2,row.col3) }
                     |> Seq.cast

但我得到:

类型不匹配。期待 IQueryable * Nullable * Nullable> -> seq * seq * seq 但给定一个 IQueryable * Nullable * Nullable> -> seq<'a>
类型 'seq<float> * seq<float> * seq<float>' 与类型 'seq<'a>'

不匹配

我做错了什么?

编辑:这是我正在尝试做的事情,听起来我的问题可能会给我一个可用的答案,但不是做我想做的事情的最佳方式。这段代码很丑但有效:

let col1 : seq<float> = query { for row in context.Table do
                                 where (row.id = 111111)
                                 select row.col1 }
                         |> Seq.cast 

let col2 : seq<float> = query { for row in context.Table do
                                 where (row.id = 111111)
                                 select row.col2 }
                         |> Seq.cast

let model = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(col1,col2)

如果我不转换为浮点数,InterpolateAkima 将无法工作,因为它不接受 Nullable 类型。不过,我不想自己对每一列进行查询。我最终的目标是拥有一个函数,我可以传入 row.id 的任何值并获取 col1、col2、col1、col3 等的模型。

我和 Mark 一样,想知道你想用它完成什么,但是尽管如此,这里有一种方法可以做到这一点:

open System
open System.Linq

// Helpers to recreate your circumstances.
type Context = { id : Int32; col1 : Nullable<Double>; col2 : Nullable<Double>; col3 : Nullable<Double>}
let context = Unchecked.defaultof<IQueryable<Context>>


let result = query { for row in context do
                     where (row.id = 111111)
                     select (row.col1,row.col2,row.col3) }


let seqTuple =
    result
    |> Seq.fold (fun (col1s, col2s, col3s) (col1, col2, col3) ->
        (if col1.HasValue then col1.Value :: col1s else col1s),
        (if col2.HasValue then col2.Value :: col2s else col2s),
        (if col3.HasValue then col3.Value :: col3s else col3s)
    ) ([], [], [])
    |> fun (col1s, col2s, col3s) ->
        List.rev col1s,
        List.rev col2s,
        List.rev col3s

本题分为两部分:

  • seq<a * b * c> 转换为 seq<a> * seq<b> * seq<c>List.unzip3Array.unzip3 就是这样做的。

  • 摆脱 Nullable:这取决于您希望在值为 null 时发生什么。

    • 如果你想 return 0 为空值:

      let col1, col2, col3 =
          query { for row in context.Table do
                  where (row.id = 111111)
                  let col1 = if row.col1.HasValue then row.col1.Value else 0.
                  let col2 = if row.col2.HasValue then row.col2.Value else 0.
                  let col3 = if row.col3.HasValue then row.col3.Value else 0.
                  select (col1, col2, col3) }
          |> Array.ofSeq
          |> Array.unzip3
      
    • 如果要忽略有空值的行:

      let col1, col2, col3 =
          query { for row in context.Table do
                  where (row.id = 111111 && row.col1.HasValue && row.col2.HasValue && row.col3.HasValue)
                  select (row.col1.Value, row.col2.Value, row.col3.Value) }
          |> Array.ofSeq
          |> Array.unzip3