我已经定义了以下功能:
calculateApproximation :: Int -> Int -> Int -> Double -> Double calculateApproximation n a r tol = if abs(((take n xs)!!(n-1)) - (((take n xs)!!(n-2)))) <= tol then ((take n xs)!!(n-1)) else calculateApproximation (n+1) a r tol where xs = unfoldr (\x -> Just(x, (x + (r/x))/2)) a
但我看到以下类型错误:
Couldn't match expected type `Int' with actual type `Double' In the second argument of `(<=)', namely `tol' In the expression: abs (((take n xs) !! (n - 1)) - (((take n xs) !! (n - 2)))) <= tol
但是tol
,当我已经将它定义为Double时,它为什么期望成为Int?或者我在这里忽略了一个完全愚蠢的错误?
最简单的解决方法是修改类型签名,以便您的初始猜测a
和计算平方根的r
数字Double
而不是Int
.
我也冒昧地将定义分解出来ys = take n xs
以简化代码.
calculateApproximation :: Int -> Double -> Double -> Double -> Double calculateApproximation n a r tol = if abs (ys!!(n-1) - ys!!(n-2)) <= tol then ys!!(n-1) else calculateApproximation (n+1) a r tol where xs = unfoldr (\x -> Just(x, (x + (r/x))/2)) a ys = take n xs
但是,正如在注释中指出的那样,n
在查找n-1
第th个元素之前,实际上并不需要获取元素.您可以申请!!
无限列表,这可以进一步简化您的代码
calculateApproximation :: Int -> Double -> Double -> Double -> Double calculateApproximation n a r tol = if abs (xs!!(n-1) - xs!!(n-2)) <= tol then xs!!(n-1) else calculateApproximation (n+1) a r tol where xs = unfoldr (\x -> Just(x, (x + (r/x))/2)) a
为了清晰起见,我可能会考虑更多的定义
calculateApproximation' n a r tol = go n where go n = let eps = abs $ xs!!(n-1) - xs!!(n-2) in if eps <= tol then xs !! (n-1) else go (n+1) xs = unfoldr (\x -> Just (x, (x + r/x)/2)) a
最后,我会发现操作go
永远只使用n-1
与n-2
列表的元素,从来没有前面的元素,该指数n
仅用于跟踪您在列表中的位置.所以我会重写,以便go
在列表上操作,而不是在索引上操作,并让它遍历列表,直到找到合适的答案.而在一个较小的整洁行动,我会从改变unfoldr
到iterate
-你只有真正想unfoldr
如果列表应该在某个点终止.
calculateApproximation a r tol = go xs where go (x:y:rest) = if abs (x-y) < tol then y else go (y:rest) xs = iterate (\x -> (x+r/x)/2) a