首页 > 解决方案 > 来自列表理解的意外返回类型

问题描述

我通过做一些简单的矩阵数学来自学一点 F#。我决定编写一组简单的函数来组合两个矩阵,因为我认为这将是学习列表推导的好方法。但是,当我编译它时,我的单元测试会产生类型不匹配异常。

//return a column from the matrix as a list
let getColumn(matrix: list<list<double>>, column:int) =
    [for row in matrix do yield row.Item(column)]
//return a row from the matrix as a list
let getRow(matrix: list<list<double>>, column:int) =
    matrix.Item(column)
//find the minimum width of the matrices in order to avoid index out of range exceptions
let minWidth(matrix1: list<list<double>>,matrix2: list<list<double>>) = 
    let width1 = [for row in matrix1 do yield row.Length] |> List.min
    let width2 = [for row in matrix2 do yield row.Length] |> List.min
    if width1 > width2 then width2 else width1
//find the minimum height of the matrices in order to avoid index out of range exceptions
let minHeight(matrix1: list<list<double>>,matrix2: list<list<double>>) = 
    let height1 = matrix1.Length
    let height2 = matrix2.Length
    if height1 > height2 then height2 else height1
//combine the two matrices
let concat(matrix1: list<list<double>>,matrix2: list<list<double>>) =
    let width = minWidth(matrix1, matrix2)
    let height = minHeight(matrix1, matrix2)
    [for y in 0 .. height do yield [for x in 0 .. width do yield (List.fold2 (fun acc a b -> acc + (a*b)), getRow(matrix1, y), getColumn(matrix2, x))]]

我期待该函数返回类型列表的列表

double list list

然而它实际返回的看起来更像是某种 lambda 表达式

((int -> int list -> int list -> int) * double list * double list) list list 

有人可以告诉我要返回什么,以及如何强制将其评估到我最初期望的列表列表中吗?

标签: f#

解决方案


你的问题有一个简短的答案和一个长答案。

简短的回答

简短的版本是 F# 函数(如List.fold2)采用多个参数,而不是像您认为的那样使用逗号,而是在它们之间使用空格。即,您不应该List.fold2这样调用:

List.fold2 (function, list1, list2)

而是像这样:

List.fold2 function list1 list2

现在,如果您只是删除List.fold2调用中的逗号,您会看到编译器抱怨您的getRow(matrix1, y)调用,并告诉您在它们周围加上括号。List.fold2(实际上不需要外面的一对括号)。所以这:

(List.fold2 (fun acc a b -> acc + (a*b)), getRow(matrix1, y), getColumn(matrix2, x))

需要变成这样:

List.fold2 (fun acc a b -> acc + (a*b)) (getRow(matrix1, y)) (getColumn(matrix2, x))

长答案

F# 函数采用多个参数的方式实际上与大多数其他语言(例如 C#)非常不同。事实上,所有 F# 函数都只采用一个参数!“但是等等,”你现在可能在想,“你刚刚向我展示了 F# 函数采用多个参数的语法!” 是的,我做到了。幕后发生的事情是curryingpartial application的结合。我会写一个很长的解释,但 Scott Wlaschin 已经写了一个,这比我能写的要好得多,所以我只是将您指向https://fsharpforfunandprofit.com/series/thinking-functionally.html系列,以帮助您了解这里发生了什么。(关于柯里化和部分应用的部分是您想要的部分,但我建议您按顺序阅读该系列,因为后面的部分建立在前面部分中介绍的概念之上)。

是的,这个“长”答案似乎比“短”答案要短,但是如果您阅读该系列(然后是 Scott Wlaschin 的其他优秀网站),您会发现它比简短答案要长得多。:-)

如果您有更多问题,我很乐意尝试解释。


推荐阅读