Adding Overloaded Constructors to Implicit F# Type

2019-08-09 12:47发布

问题:

I have created the following type using implicit type construction:

open System

type Matrix(sourceMatrix:double[,]) =
  let rows = sourceMatrix.GetUpperBound(0) + 1
  let cols = sourceMatrix.GetUpperBound(1) + 1
  let matrix = Array2D.zeroCreate<double> rows cols
  do
    for i in 0 .. rows - 1 do
    for j in 0 .. cols - 1 do
      matrix.[i,j] <- sourceMatrix.[i,j]

  //Properties

  ///The number of Rows in this Matrix.
  member this.Rows = rows

  ///The number of Columns in this Matrix.
  member this.Cols = cols

  ///Indexed Property for this matrix.
  member this.Item
    with get(x, y) = matrix.[x, y]
     and set(x, y) value = 
        this.Validate(x,y)
        matrix.[x, y] <- value

  //Methods
  /// Validate that the specified row and column are inside of the range of the matrix.
  member this.Validate(row, col) =
    if(row >= this.Rows || row < 0) then raise (new ArgumentOutOfRangeException("row is out of range"))
    if(col >= this.Cols || col < 0) then raise (new ArgumentOutOfRangeException("column is out of range"))

However now I need to add the following overloaded constructor to this type (which is in C# here):

public Matrix(int rows, int cols)
    {
        this.matrix = new double[rows, cols];
    }

The problem that I have is that it seems any overloaded constructors in an implicit type must have a parameter list that is a subset of the first constructor. Obviously the constructor I want to add does not meet this requirement. Is there any way to do this using implicit type construction? Which way should I do this? I'm pretty new to F# so if you could show the whole type with your changes in it I would greatly appreciate it.

Thanks in advance,

Bob

P.S. If you have any other suggestions to make my class more in the functional style please feel free to comment on that as well.

回答1:

I would probably just do this:

type Matrix(sourceMatrix:double[,]) =
  let matrix = Array2D.copy sourceMatrix
  let rows = (matrix.GetUpperBound 0) + 1
  let cols = (matrix.GetUpperBound 1) + 1

  new(rows, cols) = Matrix( Array2D.zeroCreate rows cols )

unless we are talking about very large arrays which are created very often (i.e. copying the empty array becomes a performance bottleneck).

If you want to emulate the C# version, you need an explicit field that can be accessed from both constructors, like so:

type Matrix(rows,cols) as this =

  [<DefaultValue>]
  val mutable matrix : double[,]
  do this.matrix <- Array2D.zeroCreate rows cols

  new(source:double[,]) as this =
    let rows = source.GetUpperBound(0) + 1
    let cols = source.GetUpperBound(1) + 1
    Matrix(rows, cols)
    then
      for i in 0 .. rows - 1 do
        for j in 0 .. cols - 1 do
          this.matrix.[i,j] <- source.[i,j]

BTW, there is also a matrix type in the F# PowerPack.