我正在尝试编写一个函数来计算2个列表的内积,即如果列表是[1,2,3]和[4,5,6]那么内积将是(1 x 4) +(2 x 5)+(3 x 6)= 4 + 10 + 18 = 32.
所以我想用zipWith
来获取产品,然后foldl
将它们与加法相加。因此zipWith
应生成[4,10,18],然后foldl
应将其加总为32。
所以我写了:
innerprod [] [] = 0
innerprod x y = foldl (+) 0 (zipWith (*) x y)
一切都在编译,但是当我在ghci中运行时:
Prelude ListFuncs> innerprod [1,2,3] [4,5,6]
<interactive>:3:1:
No instance for (Num
([c0] -> (a0 -> b0 -> a0) -> a0 -> [b0] -> a0))
arising from a use of `innerprod'
Possible fix:
add an instance declaration for
(Num ([c0] -> (a0 -> b0 -> a0) -> a0 -> [b0] -> a0))
In the expression: innerprod [1, 2, 3] [4, 5, 6]
In an equation for `it': it = innerprod [1, 2, 3] [4, 5, 6]
由于错误消息,我尝试制作这样的代码,但在编译时会返回不同的错误:
innerprod :: Num [Int] => (Int -> Int -> Int) -> Int -> [Int] -> Int
innerprod [] [] = 0
innerprod x y = foldl + 0 (zipWith (*) x y)
有谁知道出了什么问题?我希望签名是innerprod :: [Int] -> [Int] -> Int
,因为它需要2个int列表并返回一个int。但这也不起作用。感谢您的时间。如果我不应该在这里问这个问题,请告诉我。
答案 0 :(得分:10)
Num [Int] => (Int -> Int -> Int) -> Int -> [Int] -> Int
是一个完整的虚假签名。这意味着:“如果任何整数列表都可以被视为一个数字[??!],我会给你一个特殊版本的折叠”。这不像你想要的内在产品,即Vector -> Vector -> Scalar
;在这种情况下Num a => [a] -> [a] -> a
。事实上,通过该签名,您的原始定义可以完美地运作:
innerProd :: Num a => [a] -> [a] -> a
innerProd x y = foldl' (+) 0 (zipWith (*) x y)
ListFuncs * GT; innerProd [1,2,3] [4,5,6]
32
我认为你不实际尝试了这个。你写的是没有围绕+
的parens。
foldl + 0 (zipWith (*) x y)
现在,这是另一头野兽。这意味着,通过将foldl
函数应用于列表的zip来将0
- 函数添加到您获得的函数中......另一个显而易见的事情。请记住,中缀运算符绑定与普通函数应用程序不同,您需要将它们打包在parens中以将它们作为函数参数传递。