简体   繁体   中英

Access to GetSlice method in F#

I'm implementing slice expressions for a matrix class in F#, which means that I have to implement three GetSlice methods. My question is about obtaining an efficient way of doing this by leveraging existing functionality from the core library. The signatures for the three methods are as follows:

member GetSlice : idx1:int * start2:int option * end2:int option -> IMatrix
member GetSlice : start1:int option * end1:int option * idx2:int -> IMatrix
member GetSlice : start1:int option * end1:int option * 
                  start2:int option * end2:int option -> IMatrix

Consider the final of these three. The matrix class has a private float[,] field called entries which holds the matrix data. The most natural implementation would be something like this:

member this.GetSlice (?start1 : int, ?end1 : int, ?start2 : int, ?end2 : int) =
    let newEntries = entries.GetSlice(?start1 = start1, ?end1 = end1,
                                      ?start2 = start2, ?end2 = end2)
    new Matrix(newEntries),

which simply uses the GetSlice functionality of the float[,] implementation. However, this does not compile, as the GetSlice extension method is not available (at least not with the namespaces I've opened). I would have thought that this method was available by default in FSharp.Core, but this doesn't really seem to be the case. A manual implementation based on slice expressions for float[,] could look something like this

member this.GetSlice (?start1 : int, ?end1 : int, ?start2 : int, ?end2 : int) =
    let newEntries = match (start1, end1, start2, end2) with
        | Some(sta1), Some(end1), Some(sta2), Some(end2) -> entries.[sta1 .. end1, sta2 .. end2]
        | Some(sta1), Some(end1), Some(sta2), None -> entries.[sta1 .. end1, sta2 .. ]
        (...)
    new Matrix(entries),

which would necessitate 16 pattern cases and is thus somewhat inconvenient. Is there an easier option, perhaps based on somehow gaining access to the GetSlice extension method of float[,] ?

You could use defaultArg to assign a values for those option and just slice with them on your array :

member __.GetSlice (?start1 : int, ?end1 : int, ?start2 : int, ?end2 : int) =
  let start1, end1, start2, end2 =
    defaultArg start1 0,
    defaultArg end1 (Array2D.length1 entries - 1),
    defaultArg start2 0,
    defaultArg end2 (Array2D.length2 entries - 1)

  new Matrix (entries.[start1 .. end1, start2 .. end2])

Extension methods are just syntactic sugar that make a static method look like an instance method.

If you hit "Go to definition" on the GetSlice extension method (I'm guessing you saw it working in another project?), you will be able to see the 'real' static method behind it. It will be something like:

public static class SomeMatrixUtilityLibrary.ExtensionMethods
{
    public static float[,] GetSlice(this float[,] array2d,
                                    int start1, 
                                    int end1,
                                    int start2,
                                    int end2)
   {
        //... 
   }
}

That static method will work just fine in F#, you'll only need to invoke it normally instead of through the extension syntax.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM