在Haskell中执行余弦定律?

时间:2019-01-28 19:45:53

标签: list function haskell list-comprehension cosine

所以我想使用以下公式创建自己的余弦函数:enter image description here

只要绝对值大于0.001,该函数就应返回该值。

但是,我的代码似乎有一些类型错误,我只是不知道如何解决。我已经尝试过将所有类型都更改为Double,但是仍然无法正常工作。

fac :: Int -> Int
fac n = if (n == 0) then 1 else n * fac (n-1)

cos :: Double -> Double
cos x = sum [cos| k <- [0..],
                  let cos = (-1) * (x^(2*k) `div` fac (2*k)) , 
                  abs (cos) > 0.001]

这是错误:

•无法将预期的类型“ Double”与实际类型“ Int”

匹配

•在“ div”的第二个参数中,即“ fac(2 * k)”

1 个答案:

答案 0 :(得分:6)

这里基本上有两个问题:

  • div仅用于整数除法(即采用整数输入,并通过舍入产生整数输出)。您需要(/)进行浮点除法。
  • fac返回一个Int,在进行除法运算之前,必须将其显式转换为浮点数。 (许多语言将自动从整数类型转换为浮点类型,但Haskell不会。)您可以使用fromIntegral进行转换。

解决了这两个问题,但除此之外,我们得到了:

fac :: Int -> Int
fac n = if (n == 0) then 1 else n * fac (n-1)

cos :: Double -> Double
cos x = sum [cos| k <- [0..],
                  let cos = (-1) * (x^(2*k) / fromIntegral (fac (2*k))) , 
                  abs (cos) > 0.001]

此类型检查(尽管还有其他问题)从最重要到最不重要依次进行:

  • 您可能希望Haskell以某种方式神奇地知道一次abs cos <= 0.001在一次迭代中,对于以后的所有迭代将继续如此,并停止迭代。但事实并非如此。您说要从k中抽出[0..],所以它将从整个列表中抽出k-永远不会完成。您可能更喜欢takeWhile
  • 您在k上失去了指数-1
  • 即使撇开这是否是最有效的公式,您的实现也会重复很多工作。每次对fac (2*k)的调用都必须重新计算以前作为中间结果所做的所有阶乘。而您的x^(2*k)会重复一些工作(尽管程度要小得多)。
  • 重用名称cos非常令人困惑。尽管从技术上讲它不会使程序错误出错,但我还是会避免使用它。

我把它留给您玩,以探索Haskell并学习如何自己解决这些问题,我认为这完全在您在此处显示的能力之内!