Haskell 哈斯凯尔分部,仍然是唐';我不明白

Haskell 哈斯凯尔分部,仍然是唐';我不明白,haskell,types,integer,int,division,Haskell,Types,Integer,Int,Division,我还是不明白哈斯克尔的分工。我的第一个意图是定义这样一个函数: piApprox :: (Integral a, Fractional b) => a -> b piApprox n = 4 * sum [ (-1)^k / (2*k + 1) | k <- [0..n] ] 但它再次引发了“无法推断”的错误 如果我在解释器中运行此代码以找出哪个签名是最好的,结果是: Prelude> let piApprox n = 4 * sum [ (-1)^k / (2*k +

我还是不明白哈斯克尔的分工。我的第一个意图是定义这样一个函数:

piApprox :: (Integral a, Fractional b) => a -> b
piApprox n = 4 * sum [ (-1)^k / (2*k + 1) | k <- [0..n] ]
但它再次引发了“无法推断”的错误

如果我在解释器中运行此代码以找出哪个签名是最好的,结果是:

Prelude> let piApprox n = 4 * sum [ (-1)^k / (2*k + 1) | k <- [0..n] ]
Prelude> :t piApprox
piApprox :: (Fractional a, Integral a) => a -> a
这是可行的,但我认为这不是最好的方法

我还认为,即使输入和输出类型在签名中都是正确的,中间操作
(-1)^k/(2*k+1)
——除法的位置——也可能是问题所在,因此我还定义了:

piApprox' :: (Fractional a) => Int -> a
piApprox' n = 4 * sum [ (fromIntegral) $ (-1)^k / (2*k + 1) | k <- [0..n] ]
piApprox':(分数a)=>Int->a

piApprox'n=4*sum[(fromIntegral)$(-1)^k/(2*k+1)| k您的问题是混合了不兼容的数字类型。您说过n是一些
整数(具体来说,在本例中是整数)。
k这应该可以:

piApprox n = 4 * sum [ fromIntegral ((-1)^k) / fromIntegral (2*k + 1) | k <- [0..n] ]
piApprox n=4*sum[from integral(-1)^k)/from integral(2*k+1)| ka->b

所以它基本上将整型转换为Num型

(/
)的类型为:

分数a=>a->a->a
,因此必须向其提供分数数据


fromIntegral
函数将通过将其转换为
Num
类型来实现这一点,该类型包括
分数
类型。

我主张此签名:

piApprox :: (Fractional a) => Int -> a
piApprox :: (Fractional r) => Int -> r
原因是,“precision”参数没有任何特定的“value”含义,它只是一个计数器,表示您愿意让函数运行多少步。(更好的方法可能是指定您希望允许的与真值π的偏差,而不是计算深度,但这更复杂。)

接下来,当前实现的冲突点实际上是
(-1)^k
(它需要
积分
,因为求幂是通过递归乘法实现的)是的,这是数学和科学中表示交替符号的常用方法,但如果你想一想,这是一种非常糟糕的方法。你对幂不感兴趣,只对符号交替感兴趣,而这在
循环[1,-1]
中更自然地实现

对于乘法,它是不同的,它根本不需要
整数
,但需要两个参数具有相同的类型。实现这一点的自然方法是,立即使用
分数
变量,而不是从整数转换!因此,您可以使用
[0..from Integral n]而不是
[0..n]
。每一步只进行一次转换,而不是一次转换

实际上,最好不要绑定索引!因为这是Haskell,所以可以将列表定义为无限(就像
cycle
也一样)。当然,不能对无限列表求和,但可以在执行此操作之前将其精简:

piApprox :: (Fractional r) => Int -> r
piApprox n = 4 * sum (take n [ σ / (2*k + 1) | (σ,k) <- zip (cycle [-1,1]) [0..] ])
这比您的实现少了一步,因为
take n[0..]
相当于
[0..n-1]
。我想这没什么大不了的,否则修复起来很简单



最后:我假设你知道这个公式在收敛速度方面非常糟糕!

你可能是指
整数而不是第一行代码上的
整数。Haskell中没有自动转换类型,因此由于结果是
b
类型,你需要转换
a
一些在这里,例如,通过使用积分k
中的
而不是
k
“我们如何将
Num
传递到
fractive
”…这对于非OO语言来说是糟糕的措辞。您不能“传递
Num
”,您可以传递恰好在
Num
类型类中的类型的对象。Haskell没有子类型,这可能是您所指的。即使如此,它也需要以另一种方式传递:“传递
分数
Num
”@leftaroundabout是的,我同意你的看法。你将如何更好地重新表述?我只想说“fromIntegral将整数转换为任何其他
Num
类型(包括分数类型)的数字”。阅读各种类型的类是你可以在其他地方做的事情。@leftaroundabout,谢谢,我想重新表述得更好。
piApprox :: (Fractional r) => Int -> r
piApprox n = 4 * sum (take n [ σ / (2*k + 1) | (σ,k) <- zip (cycle [-1,1]) [0..] ])
piApprox n = (4 *) . sum $
    take n [ σ / (2*k + 1) | σ <- cycle [1, -1]
                           | k <- [0..]
           ]