我可以在 F# 中直接使用元组作为 Array2D 索引吗?

Can I directly use a tuple as an Array2D index in F#?

假设我有以下 Array2D

> let arr = Array2D.init 2 3 (fun i j -> (i+1) * (j+2));;
> printfn "%A" arr
[[2; 3; 4]
 [4; 6; 8]]

我知道我可以像这样访问数组元素

> arr[1, 2];;
8

但是如果我将坐标保存在一个元组中呢?为什么我不能执行以下操作或类似操作:

> let coord = (1, 2);;
> arr[coord]
    Error: input.fsx (2,1)-(2,11) typecheck error This expression was expected to have type
    ''a[]'    
but here has type
    'int[,]'    

每次使用元组之前都要先解包,感觉有点蠢。或者这是唯一的方法?

> let x, y = coord;;
> arr[x, y];;
8

我认为没有任何直接的方法可以使用元组索引二维数组。一种类似的替代方法是使用 Map 代替:

let map =
  seq {
    for i = 0 to 1 do
      for j = 0 to 2 do
        yield (i, j), (i+1) * (j+2)
  } |> Map

let coord = (1, 2)
map[coord]   // 8

您始终可以使用 ||> 来解包元组,而不是使用 let 表达式和 Array2D.get。缺点是它肯定更冗长。

- let arr = Array2D.init 2 3 (fun i j -> (i+1) * (j+2))
- let coord = (1,2)
- coord ||> Array2D.get arr;;

val it : int = 8

F# 以特殊方式处理元组参数。如果方法不是在 F# 中定义的,那么它的参数应该是元组:

System.String.Join(", ", [|1; 2; 3|])
System.String.Join ", " [|1; 2; 3|] // not valid

这样做是为了帮助解决重载问题。

你可以做的是扩展多维数组类型:

type ``[,]``<'a> with
    member inline ar.Item with get ((x, y): (int*int)) : 'a =
        ar.[x, y]

然后使用它:

let coord = (1, 2)
arr.Item coord |> printfn "%d"

不幸的是 arr.[coord] 不可用并且看起来像是编译器中的错误

所有问题都通过函数解决!

let xss = Array2D.init 2 3 (fun i j -> (i+1) * (j+2));;
let get arr (x,y) = Array2D.get arr x y

get xss (1,2) (* Returns 8 *)