Haskell:Double和Int之间的变量类型混淆

Haskell:Double和Int之间的变量类型混淆,haskell,types,Haskell,Types,作为uni赋值,我应该编写一个带有类型声明的函数: pi_approx :: Int -> Double 这是我第一次尝试: pi_approx :: Int -> Double pi_approx x = let total = sum [1 / (y^2) | y <- [1..x]] in sqrt (6 * total) 到目前为止还不错 level2 :: (Enum a, Fractional a) => a -> [a] level2 x

作为uni赋值,我应该编写一个带有类型声明的函数:

pi_approx :: Int -> Double
这是我第一次尝试:

pi_approx :: Int -> Double
pi_approx x = let total = sum [1 / (y^2) | y <- [1..x]]
    in sqrt (6 * total)
到目前为止还不错

level2 :: (Enum a, Fractional a) => a -> [a]
level2 x = [level1 y | y <- [1..x]]

没有看到Int

level4 :: (Enum a, Fractional a) => a -> a
level4 x = 6 * (level3 x)
最后

level5 :: (Floating a, Enum a) => a -> a
level5 x = sqrt (level4 x)
我已经从这个兔子洞里钻了出来,但我还没有找到答案。我用integral的
运行它

pi_approx :: Int -> Double
pi_approx x = let total = sum [(fromIntegral 1) / ((fromIntegral y)^ (fromIntegral 2)) | y <- [1..x]]
    in sqrt (6*total)
pi_近似值::Int->Double

pi_近似x=let total=sum[(from integral 1)/(from integral y)^(from integral 2))|y由于类型类的类型检查方式,显示的类型错误不是最有用的

[ 1 / (y^2) | y <- [1..x] ]
也就是说,它在两侧都接受相同的类型,并且也返回它。因此,只要知道
y^2
的类型是
Int
,我们就推断
1
,整个表达式也是
Int
。只有在稍后的约束检查阶段,GHC才会确保
Int
分数的,当然不是。例如:

recp :: Int -> Int
recp x = 1 / x
会给你一个更好的错误

• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: 1 / x
  In an equation for ‘recp’: recp x = 1 / x
但在检查函数时,它并没有走那么远,因为首先出现了类型统一失败

有时,如果您无法找出错误,删除签名并查看推断的类型会很有帮助(通常情况下,添加更多类型签名会很有帮助,但并不总是如此)

如果没有签名,函数实际上会进行类型检查。它也可以工作:

ghci> pi_approx 100
3.1320765318091053
此处
100
默认为
Double
,以满足
分数约束,整个定义以
Double
s的形式进行

只是它不接受
Int
s:

ghci> pi_approx (100 :: Int)

<interactive>:1:1: error:
• No instance for (Floating Int) arising from a use of ‘pi_approx’
• In the expression: pi_approx (1 :: Int)
ghci>pi_近似值(100::Int)
:1:1:错误:
•没有因使用“pi_近似值”而产生的(浮点整数)实例
•在表达式中:pi_近似值(1::Int)

您定义的所有级别函数都有类型
a->a
(或
a->[a]
)以及对
a
的一些约束。因此,在所有情况下,输出的类型都将是进入的类型(或其列表)

因此,当调用每个
级别
函数时,有两种可能的结果:要么调用类型错误,因为参数的类型不满足约束条件;要么返回相同时间的值(或其列表)。无论哪种方式,你都不可能输入一个
Int
,然后返回一个
浮点值


So
sqrt(共6个)
被视为
Int
,因为,正如我们刚才讨论的,输出的类型将与输入的类型相同,输入的类型是
Int
。现在输入的类型实际上不满足约束条件,因此您可能会在这方面出现错误。如果没有类型签名,您将完全得到该错误(使用类型为
Int
的参数调用函数后)。但是使用类型签名,在检查约束之前会检测到返回类型不匹配的错误,这就是为什么会出现该错误。

每个人都解释了错误的原因,但没有人告诉您如何修复它。

下面是如何修复代码以使其正常工作

pi_approx :: Int -> Double
pi_approx x = let total = sum [1 /(fromIntegral (y^2)) | y <- [1..x]]
    in sqrt (6 * total)
pi_近似值::Int->Double

pi_约x=总=和[1/(从积分(y^2))|是的,我真的很喜欢你为实验制定的计划。观察:在进行测试时,你将所有的类型签名都改为多态的,而不是具体的。如果你从具体的类型
level1::Int->Double
开始,它会让你停滞不前(或者,如果您从具体类型
level1::Double->Double
开始,那么您很快就会发现
level5
的类型签名中没有
Int
)。数字常量(如1、2、6)可能有任何数字类型。您可以在_ghci_u解释器中检查这一点,输入“:type 6”。因此,您只需要
(from integral y)
转换器。参数x上的
Int
类型约束未过渡到y。因此,初始代码中的类型冲突位于“/”级别运算符。不像C++中的Fortran,没有自动的数字类型的升级。你必须让它明确地发生。@丹尼尔瓦格纳怀疑这些定义是没有签名的,而多态类型是从GHCi的<代码>:t< /Cort>命令中复制的。r答案没有回答问题。
(/)的类型
和其他答案一样满意。你提到的注释在这方面是错误的。@Willence实际上似乎你可能弄错了。请记住,OP强制键入
pi\u approx::Int->Double
。让我们看看如果我强制
Int
进入函数
//code>会发生什么。在我的GHCI版本中,出现以下情况:
Prelude>x=5::Int
Prelude>1/x
:4:1:错误:
•没有(分数Int)的实例由于使用了“/”
•在表达式中:1/x
在“it”的等式中:it=1/x
,所以我和GHCI似乎有所不同。感谢您花时间阅读我的评论,整个测试对我很有指导意义。@CarstenS您认为
(来自积分1)/((fromIntegral y)^(fromIntegral 2))
是比
1/(fromIntegral(y^2))
更好的解决方案?从表面上看,这似乎是一个美学问题,但经过深入检查,您会发现
1/(fromIntegral(y^2))
触及问题的核心;即,由于以下
pi_近似::Int->Double
被强制执行,问题在于
y
,因此
(from integral 1)/((from integral y y)^(from integral 2))
是一个“即插即用工程师特别解决方案”,而我的
• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: 1 / x
  In an equation for ‘recp’: recp x = 1 / x
ghci> :t pi_approx
pi_approx :: (Floating a, Enum a) => a -> a
ghci> pi_approx 100
3.1320765318091053
ghci> pi_approx (100 :: Int)

<interactive>:1:1: error:
• No instance for (Floating Int) arising from a use of ‘pi_approx’
• In the expression: pi_approx (1 :: Int)
pi_approx :: Int -> Double
pi_approx x = let total = sum [1 /(fromIntegral (y^2)) | y <- [1..x]]
    in sqrt (6 * total)