我一直在尝试编写一个curried函数“multvec”,它使用u =(u1,u2,...,un)和v =(v1,v2,...,vn)并输出u1 * v1 + u2 * v2 + ... + un * vn。我认为我的逻辑大多是正确的(至少它会在其他语言中......)但我一直得到:
stdin(11,57): error FS0001: This expression was expected to have type
'a list
but here has type
'c list * 'd list -> 'b list
代码如下:问题显然在最后一行的产品调用中。但是,我的印象是基本情况(x * y):: []只会产生一个列表,而不是它实际生成的列表。
let rec multvec xs ys = function
| [ ], [ ] -> failwith "Both lists cannot be empty"
| x::[ ], y::[ ] -> ( x * y )::[ ]
| x::xs, y::ys -> let product = multvec xs ys
( x * y ) + ( List.reduce (+) product )
对此错误的任何明确性将不胜感激!先感谢您。
答案 0 :(得分:8)
你的代码老实说它的错误比正确:; - ]
function
和xs
是单独的参数时使用ys
List.reduce
在单个元素列表上运行 - 稍微向后; - ] 这是一个明智的实现,修复了以上所有内容:
let inline multvec xs ys = List.map2 (*) xs ys |> List.sum
请注意,如果性能是主要关注点,则可能值得避免使用List.sum
,因为它使用了检查算术。如果使用未经检查的算术可以,则可以执行以下操作:
let inline multvec xs ys = List.map2 (*) xs ys |> List.reduce (+)
如果您真的想手动执行此操作,可以采用以下方法之一:
let inline multvec xs ys =
let rec impl acc = function
| [], [] -> acc
| x::xs', y::ys' -> impl (x * y + acc) (xs', ys')
| _ -> failwith "lists must be of equal length"
impl LanguagePrimitives.GenericZero (xs, ys)
答案 1 :(得分:1)
要添加到ildjarn的答案,您可以使用map2
将reduce
和fold2
融合到单个函数调用中,以计算两个向量的点积(“multvec”):
let inline dot xs ys =
let zero = LanguagePrimitives.GenericZero
List.fold2 (fun acc x y -> acc + x * y) zero xs ys
这样可以避免创建不必要的临时列表。