简体   繁体   English

Haskell 类型签名 pi

[英]Haskell type signature pi

I am very new to Haskell and functional programming.我对 Haskell 和函数式编程非常陌生。

I want to approximate pi with a programm.我想用一个程序来近似 pi。 My code works but only without the type-signature.我的代码有效,但只有没有类型签名。 Yet the task is to write a list-comprehension that fits the given type-signature so I probably have to change sth in my list-comprehension.然而,任务是编写一个适合给定类型签名的列表理解,所以我可能不得不改变我的列表理解中的某事。

pi_approx :: Int -> Double

pi_approx n = sqrt (6 * (sum [1 / x^2 | x <- [1..n]])) 

The reason that this does not work with the signature Int -> Double is because functions like (*):: Num a => a -> a -> a and sqrt:: Floating a => a -> a require that the operand(s) and the result all have the same type.这不适用于签名Int -> Double的原因是因为(*):: Num a => a -> a -> asqrt:: Floating a => a -> a等函数要求操作数(s) 和结果都具有相同的类型。

This thus means that if n is an Int , then x in x <- [1..n] is also an Int , and since the type signature of (^) is (^):: (^):: (Integral b, Num a) => a -> b -> a , it means that x ^ 2 has the same type as x , and this is thus an Int as well.因此,这意味着如果nInt ,则x in x <- [1..n]也是Int ,并且由于(^)的类型签名是(^):: (^):: (Integral b, Num a) => a -> b -> a ,这意味着x ^ 2x具有相同的类型,因此这也是一个Int

The problem that now arises is that (/):: Fractional a => a -> a -> a requires the type to a member of the Fractional typeclass, and an Int is is not Fractional .现在出现的问题是(/):: Fractional a => a -> a -> a需要类型为Fractional类型类的成员,而Int is 不是Fractional

We can make use of fromIntegral:: (Integral a, Num b) => a -> b to convert a value from a type that is a member of the Integral typeclass to value with a type that is a member of the Num typeclass.我们可以使用fromIntegral:: (Integral a, Num b) => a -> b将值从Integral类型类的成员类型转换为具有Num类型类成员类型的值。

We thus can fix this problem with:因此,我们可以通过以下方式解决此问题:

pi_approx :: Int -> Double
pi_approx n = sqrt (6 * (sum [1 / fromIntegral (x^2) | x <- [1..n]]))

if x can be large, it makes sense, as @dfeuer says , to convert x to a double before calculating the square:如果x可以很大,正如@dfeuer 所说,在计算平方之前将x转换为 double 是有意义的:

pi_approx :: Int -> Double
pi_approx n = sqrt (6 * (sum [1 / fromIntegral x^2 | x <- [1..n]]))

This then produces:这会产生:

Prelude> pi_approx 1
2.449489742783178
Prelude> pi_approx 2
2.7386127875258306
Prelude> pi_approx 10
3.04936163598207
Prelude> pi_approx 20
3.094669524113704
Prelude> pi_approx 100
3.1320765318091053
Prelude> pi_approx 200
3.136826306330968
Prelude> pi_approx 1000
3.1406380562059946

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM