f# - 来自列表理解的意外返回类型
问题描述
我通过做一些简单的矩阵数学来自学一点 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# 函数(如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# 函数采用多个参数的语法!” 是的,我做到了。幕后发生的事情是currying和partial application的结合。我会写一个很长的解释,但 Scott Wlaschin 已经写了一个,这比我能写的要好得多,所以我只是将您指向https://fsharpforfunandprofit.com/series/thinking-functionally.html系列,以帮助您了解这里发生了什么。(关于柯里化和部分应用的部分是您想要的部分,但我建议您按顺序阅读该系列,因为后面的部分建立在前面部分中介绍的概念之上)。
是的,这个“长”答案似乎比“短”答案要短,但是如果您阅读该系列(然后是 Scott Wlaschin 的其他优秀网站),您会发现它比简短答案要长得多。:-)
如果您有更多问题,我很乐意尝试解释。
推荐阅读
- c++ - 在另一个类中使用类模板的错误
- python - 如何使用外键关系更新特定字段
- mqtt-vernemq - 有没有办法从内存中逐出 vernemq 缓存的 auth_on_register、auth_on_publish、auth_on_subscribe 挂钩数据
- sql - PostgreSQL 中有多个重复值。我只想在这里获取最新的。我应该怎么办?
- certificate - 无法安装 Vpn 和应用程序用户证书
- c# - Db2:c# Nhibernate 使用时间列作为 TimeAsTimeSpan 引发异常
- postgresql - 从 pg_dump 导入 Postgres 会引发不存在字符的错误:“ÿ_”处或附近的语法错误
- powershell - 脚本分析器未使用 DSC 参数警告
- node.js - 是否可以在 Node.js “本机”中签署数据(不使用对 OpenSSL 的外部调用)?
- android - Jetpack Compose 将文本内容对齐到 Scaffold 的中心