2013-03-02 61 views
1

我一直在尝试编写一个使用u =(u1,u2,...,un)和v =(v1,v2,..., vn)并输出u1 * v1 + u2 * v2 + ... + un * vn。我觉得我有逻辑大多正确的(至少它会在其他语言...),但我不断收到:F#函数 - 预期类型与实际不同

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) 

任何澄清这个错误将不胜感激!先谢谢你。

回答

8

您的代码诚实比正确更错的:; - ]

  • 这不是尾递归
  • 使用functionxsys是独立的参数
  • 不完整的模式匹配
  • 将一个分支评估为一个列表并将另一个分支评估为标量
  • 所有产品都手动添加在一起,最后,它拥有一个单元素列表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) 
+0

谢谢!您列出的所有方法都非常出色。我想我需要阅读更多介绍F#的文档,因为它与我习惯的其他语言非常不同。 – wmarquez 2013-03-03 07:21:00

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 

这を你不需要创建一个不必要的临时列表。

+0

+1我在记事本中工作,忘记了所有关于'fold2'的问题 - 我想我太依赖于Intellisense了。 :-P – ildjarn 2013-03-06 19:32:00

+0

可以理解;我也是IntelliSense成瘾者......;) – Frank 2013-03-07 22:04:14

相关问题