我在Haskell中遇到以下错误: “仅在具有ScopedTypeVariables的模式中允许类型签名” 我应该如何重用已定义的变量。预先感谢
sum :: (Double -> Double) -> (Double -> Double) -> Int ->
(Double -> Double)
sum f g n = (\x -> helper f g n x)
where
helper :: (Double -> Double) -> (Double -> Double) -> Int -> Double ->
Double
|n == 0 = 0
|mod n 2 == 1 = f(x) + helper f g n-1 f(x)
|otherwise = g(x) + helper f g n-1 g(x)
答案 0 :(得分:5)
这实际上看起来更像是一个语法错误:您从未为helper
定义函数 body ,确实定义了helper
的签名,后跟了警卫({ {1}}部分,但您应再次声明| ...
。
此外,我认为在此处为helper f g n x = ...
和变量helper
定义变量f
是没有用的,因为在整个递归过程中这些变量都是固定的。
您可以将函数定义为:
g
我们在这里定义了两个“辅助”函数sumfg :: (Double -> Double) -> (Double -> Double) -> Int -> Double -> Double
sumfg f g = helperf
where helperf 0 _ = 0
helperf i x = let fx = f x in fx + helperg (i-1) fx
helperg 0 _ = 0
helperg i x = let gx = g x in gx + helperf (i-1) gx
和helperf
,helperg
将helperf
与f x
进行汇总,而helperg (i-1) (f x)
相同,除了我们使用helperg
代替g
。因此,我们在这里使用相互递归来解决问题。
但是,通过使用scanl :: (b -> a -> b) -> b -> [a] -> [b]
,take :: Int -> [a]
和sum :: Num a => [a] -> a
,我们可以更优雅地解决此问题:
f
因此,我们在此创建sumfg :: Num a => (a -> a) -> (a -> a) -> Int -> a -> a
sumfg f g n x = sum (take n (scanl (flip ($)) (f x) (cycle [g, f])))
和g
的无限列表,就像f
和[g, f, g, f, g, f, ...]
一样。然后,每次将累加器应用于其中一个函数时,我们就使用cycle [f, g]
并产生该元素。我们将列表中的前scanl (flip ($))
个项与n
一起使用,最后使用take n
来汇总这些值。
例如:
sum
由于Prelude> sumfg (2+) (3*) 5 1
91
是(2+1) + (3*(2+1)) + (2+(3*(2+1))) + (3*(2+(3*(2+1)))) + (2+(3*(2+(3*(2+1)))))
。
我们还概括了签名:现在,我们可以使用类型为91
的两个函数a
和f
的任何数字类型g
。