使用管道迭代 Matrix 中的列

Iteration over columns in Matrix using piping

我试图将矩阵除以它的最后一行(每列除以它的最后一个元素 - 也称为齐次坐标),然后 return 子矩阵包含除最后一行以外的所有内容。 在 Matlab 中是这样的:

normx = bsxfun(@rdivide,A,A(end,:));
output = normx(1:end-1,:);

由于我是 F# 的新手,我对任何事情都不是很确定,但我尝试了这个:

let hnorm(A:Matrix<double>) = 
    let partialResult = A |> Matrix.iterCols (fun col -> col/col.[col.Count-1])
    partialResult.Rows(0,3)

但是我在 lambda 表达式中得到了“This expression was expected to have type 'unit' but here has type 'Vector< double >'”错误。

而且我不明白哪里出了问题,因为像

这样的例子
let result = [2;4;6] |> List.map (fun x -> x * x * x)

工作顺利。

有人可以解释一下如何做到这一点,因为我认为我缺少一些基础知识或误解了它们。

谢谢!

如果您查看 Matrix.iterCols 的签名(将鼠标悬停在您的 IDE 上),您会看到它采用的参数是一个函数 Vector<'a> -> unit - 即,它是一个以 Vector<'a> 作为参数并且 return 是 unit 的函数。

另一方面,您的函数 fun col -> col/col.[col.Count-1] 实际上 return 是一个 Vector<_>,因为那是除法的结果。由于 Vector<_> 不是 unit,编译器会抱怨:"this value was expected to have type 'unit', but here has type Vector<>"。这就是编译器试图告诉你的。

根据 F# 约定,名为 iter* 的函数通常表示 "go over this sequence and produce some side-effect for every element",其中副作用可能类似于打印到屏幕或修改内存单元等。这就是为什么 iterCols 的参数预期为 return unit 的原因:它的唯一目的是产生副作用,它不应该 return 任何有用的值。

但是您想要做的是而不是产生副作用。您要做的是创建另一个 Matrix,它将所有列除以最后一个元素。这种通过对容器的每个元素应用一些函数来转换容器的操作在函数式编程中传统上称为 "map"。瞧:实际上有一个函数 Matrix.mapCols,它完全符合您的期望:

let partialResult = A |> Matrix.mapCols (fun idx col -> col/col.[col.Count-1])

注意mapCols的参数应该有两个参数而不是一个:第一个是列索引,第二个是列本身。