1

我一直在尝试编写一个柯里化函数“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 )::[ ] 只会产生一个 'a 列表,而不是它实际产生的结果。

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 )

对此错误的任何澄清将不胜感激!先感谢您。

4

2 回答 2

8

老实说,您的代码错误多于正确:;-]

  • 它不是尾递归的
  • 使用functionwhenxsys是单独的参数
  • 不完整的模式匹配
  • 让一个分支评估为列表,另一个评估为标量
  • 所有产品都是手动添加在一起的,除了最后一个,它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)
于 2013-03-02T05:16:58.280 回答
1

要添加到 ildjarn 的答案,您可以融合map2reduce使用单个函数调用fold2来计算两个向量的点积(“multvec”):

let inline dot xs ys =
    let zero = LanguagePrimitives.GenericZero
    List.fold2 (fun acc x y -> acc + x * y) zero xs ys

这将使您免于创建不必要的临时列表。

于 2013-03-05T10:14:03.573 回答