生成器,选择器模式以计算Haskell中的近似值

时间:2019-03-30 11:37:45

标签: haskell

我正在尝试实现生成器,选择器模式以近似计算haskell中的平方根

我的生成器如下:

generator :: (Double -> Double) -> Double -> [Double]
generator f a           = generator f (f a)

我的选择器:

selector :: Double -> [Double] -> Double
selector eps (a : b : r)
  | abs(a - b) <= eps   = b
  | otherwise           = selector eps (b : r)

和近似函数:

next :: Double -> Double -> Double
next n x                = (x + n/x) / 2

selector 0.1 (generator (next 5) 2)这样称呼 应该给我...(next 5( next 5 (next 5 2))),所以[2.25, 2.23611111111111, 2.2360679779158,...]因为我的eps参数是0.1 abs(a - b) <= eps应该在第一次执行时为true,因此给我2.23611111111111。但是,我确实会陷入无尽的循环。

有人可以向我解释这些功能的实现有什么问题吗?

预先感谢

2 个答案:

答案 0 :(得分:4)

此定义

generator f a = generator f (f a)

永远不会生成任何列表元素:它会陷入无限递归中。你可能想要

generator f a = a : generator f (f a)

这使a成为第一个元素,随后是我们使用递归生成的所有其他元素。

避免在列表中放入未经评估的重击也是有益的。为避免这种情况,可以使用

generator f a = a `seq` (a : generator f (f a))

,以便a得到较早的评估。在您的代码中,这无关紧要,因为 选择器一生成它们,便立即评估它们。

答案 1 :(得分:3)

正如chi's answer正确指出的那样,您的生成器函数缺少a:。但是,有一个比仅添加方法更好的解决方案。完全摆脱generator,而改用内置方法iterate(或iterate' from Data.List,以避免不必要的重击)。这些方法具有与generate相同的行为,但支持list fusion这样的优化,而您自己的方法则不会。当然,还有一个优点是,您不必编写和维护该函数即可。