首页 > 解决方案 > 在 Haskell 中实现余弦定律?

问题描述

所以我想用这个公式创建我自己的余弦函数:在此处输入图像描述

只要其绝对值大于 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”匹配</p>

• 在'div'的第二个参数中,即'fac (2 * k)'</p>

标签: listfunctionhaskelllist-comprehensiontrigonometry

解决方案


这里基本上有两个问题:

  • 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 并学习如何自己解决这些问题——我认为这完全在你在这里展示的能力范围内!


推荐阅读