2013-03-02 67 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

相關問題