F# 初始化类的函数方法

F# 初始化类的函数方法,f#,functional-programming,F#,Functional Programming,我对F#还不熟悉,所以我热衷于尝试以更实用的方式来处理问题(而不是用我习惯的命令式思维) 对于这个问题,我正在从Excel中读取数据,其中包含约6000行数据,包含多个字段(年龄、性别、性别等) 我正在使用一个类将这些数据点存储在下面的-extract中: type datastore(array:obj[,], row)= let id=array.[row,1]:?> string; let gender=array.[row,2] :?> string;

我对F#还不熟悉,所以我热衷于尝试以更实用的方式来处理问题(而不是用我习惯的命令式思维)

对于这个问题,我正在从Excel中读取数据,其中包含约6000行数据,包含多个字段(年龄、性别、性别等)

我正在使用一个类将这些数据点存储在下面的-extract中:

type datastore(array:obj[,], row)=
    let id=array.[row,1]:?> string;
    let gender=array.[row,2] :?> string;
    let sex = array.[row,3] :?> string;
    //...continues for a number of other cases
我目前正在使用以下代码初始化这些类,这些代码运行良好,但这是一种必要的方法:

let DataPoints = 
    let DataInput = //function to read data in from Excel
    [for i in DataInput.GetLowerBound(0) .. DataInput.GetUpperBound(0) -> 
        new datastore(DataInput,i)]
我的问题是,我如何才能以一种更实用的方式做到这一点

我尝试了以下方法(不起作用:给出的错误只是“由于错误而停止”)

我还查看了以下链接,这些链接似乎没有完全帮助

我不会说它“功能更少或更强大”<代码>数据点在第二个代码段中是一个列表,其中包含由F#机制初始化的
数据存储

如果希望
DataPoints
改为
数据存储
值的数组,由标准库函数初始化,相应的代码可能如下所示

let DataPoints =
   let (il,ih) = (DataInput.GetLowerBound(0),DataInput.GetUpperBound(0)) in
   Array.init (ih - il + 1) (fun x -> new datastore(DataInput, x + il))
为了采用给定的
Array.init
元素索引处理,从
0
元素数-1
DataInput.GetLowerBound(0)
DataInput.GetUpperBound(0)-DataInput.GetLowerBound(0)

但这两种方法都是函数式编程的一种形式,用于生成元素序列。

我不会将其称为“少功能或多功能”<代码>数据点在第二个代码段中是一个列表,其中包含由F#机制初始化的
数据存储

如果希望
DataPoints
改为
数据存储
值的数组,由标准库函数初始化,相应的代码可能如下所示

let DataPoints =
   let (il,ih) = (DataInput.GetLowerBound(0),DataInput.GetUpperBound(0)) in
   Array.init (ih - il + 1) (fun x -> new datastore(DataInput, x + il))
为了采用给定的
Array.init
元素索引处理,从
0
元素数-1
DataInput.GetLowerBound(0)
DataInput.GetUpperBound(0)-DataInput.GetLowerBound(0)


但这两种方法都是函数式编程的形式,用于生成元素序列。

函数式编程是每个人都有自己的定义的东西之一。如果你问我,两个突出的品质是:

  • 从类型的角度思考问题(称之为类型驱动、类型优先编程或其他)
  • 将逻辑视为由可组合步骤组成的数据转换管道
所以,如果我遇到像您这样的问题,我会首先定义数据的强类型表示。记录比类更适合存储“哑”数据,所以我会使用:

type DataPoint = 
    {
        Id:     string
        Gender: GenderType
        Sex:    SexType
    }
    static member FromRow(row: obj []) = 
        {
            Id     = row.[0] :?> string
            Gender = GenderType.Parse <| (row.[1] :?> string)
            Sex    = SexType.Parse <| (row.[2] :?> string)
        } 
有了这些,我们就有了所需的一切,现在就把它们放在一条管道中:

let dataPoints = 
    let input = //function to read data in from Excel
    input
    |> Array2D.intoRows
    |> Seq.map DataPoint.FromRow
    |> Array.ofSeq

这样就很容易看到发生了什么。您可以在每个步骤中轻松地剖析数据,扩展代码也很简单。例如,如果要将这些记录转换为一个类(例如viewmodel),这只是要添加到此处的另一个
map
步骤

函数式编程是每个人都有自己定义的东西之一。如果你问我,两个突出的品质是:

  • 从类型的角度思考问题(称之为类型驱动、类型优先编程或其他)
  • 将逻辑视为由可组合步骤组成的数据转换管道
所以,如果我遇到像您这样的问题,我会首先定义数据的强类型表示。记录比类更适合存储“哑”数据,所以我会使用:

type DataPoint = 
    {
        Id:     string
        Gender: GenderType
        Sex:    SexType
    }
    static member FromRow(row: obj []) = 
        {
            Id     = row.[0] :?> string
            Gender = GenderType.Parse <| (row.[1] :?> string)
            Sex    = SexType.Parse <| (row.[2] :?> string)
        } 
有了这些,我们就有了所需的一切,现在就把它们放在一条管道中:

let dataPoints = 
    let input = //function to read data in from Excel
    input
    |> Array2D.intoRows
    |> Seq.map DataPoint.FromRow
    |> Array.ofSeq

这样就很容易看到发生了什么。您可以在每个步骤中轻松地剖析数据,扩展代码也很简单。例如,如果要将这些记录转换为一个类(例如viewmodel),这只是要添加到此处的另一个
map
步骤

使用ExcelProvider:感谢链接。如果我继续我目前的方法,你对我的具体问题有什么更一般的指导吗?你的代码看起来不错。为什么你认为这是必要的?使用ExcelProvider:谢谢你的链接。如果我继续我目前的方法,你对我的具体问题有什么更一般的指导吗?你的代码看起来不错。为什么你认为这是必要的?如果我想使用
Array.init
,我会这么做,但值得注意的是,在这种情况下,列表理解看起来简单多了:-)如果我想使用
Array.init
,我会这么做,但值得注意的是,在这种情况下,这份清单的理解看起来简单多了:-)性别和性别都太复杂了,无法用一个歧视性的结合来正确处理。在大多数情况下,最好不要与他们打交道!性别和性别都太复杂了,无法在一个受歧视的联盟中妥善处理。在大多数情况下,最好不要与他们打交道!