F#功能 - 预期类型与实际不同

wma*_*uez 1 f# f#-scripting f#-3.0

我一直试图写一个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
Run Code Online (Sandbox Code Playgroud)

代码如下:问题显然在最后一行的产品调用中.但是,我的印象是基本情况(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 )
Run Code Online (Sandbox Code Playgroud)

任何关于此错误的清晰度将不胜感激!先感谢您.

ild*_*arn 8

你的代码老实说它的错误比正确:; - ]

  • 它不是尾递归的
  • 使用functionwhen xsys是单独的参数
  • 不完整的模式匹配
  • 让一个分支评估到一个列表,另一个分支评估为标量
  • 所有产品都是手动添加在一起的,除了最后一个产品,它List.reduce在单个元素列表上运行 - 略微向后; - ]

这是一个明智的实现,修复了以上所有内容:

let inline multvec xs ys = List.map2 (*) xs ys |> List.sum
Run Code Online (Sandbox Code Playgroud)

请注意,如果性能是主要关注点,那么可能值得避免List.sum,因为它使用了检查算术.如果使用未经检查的算术可以,则可以执行以下操作:

let inline multvec xs ys = List.map2 (*) xs ys |> List.reduce (+)
Run Code Online (Sandbox Code Playgroud)

如果你真的想手动完成这个,这里有一种方法:

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)
Run Code Online (Sandbox Code Playgroud)