我正在做一种新的类型,这样我就能精确地计算出大的数字。基本上,表示数字为Double * 10 ^ Integer
的是一个双整数和一个整数。现在我开始制作程序,它一直是"ok“,直到我尝试创建一个新数字的实例,这样我就可以简单地使用+
来添加我的新数字了。这使我更容易在我现有的程序中使用。但我只是从我的代码中得到了一个类似于“无法推断”的错误(我将在下面发布一个示例)。我有点理解这个错误,但我似乎可以回避这个问题。如果希望编译代码,请注释第4和第5行。
我已经做了好几个小时了,我要“杀了”我。
newtype Sci f p = Sci (f ,p) deriving (Eq,Show)
instance (Floating a,Integral b) => Num (Sci a b) where
Sci (a,b) * Sci (c,d) = fixSci( Sci(a*c,b*d) )
mulSci :: Sci Double Integer -> Sci Double Integer -> Sci Double Integer
mulSci (Sci(a,b)) (Sci(c,d)) = fixSci (Sci(a*c,b*d))
mkSci :: Double -> Sci Double Integer
mkSci 0 = Sci(0, 0)
mkSci n = let lg = (floor ((log10 . abs) n)) in Sci((n/(10**(fromIntegral lg))), if lg > 0 then lg else 0)
fixSci :: Sci Double Integer -> Sci Double Integer
fixSci (Sci(a,b)) = let n = mkSci a in (\(Sci(c,d)) -> Sci(c,b+d)) n
fromSci (Sci(a,b)) = a*10**(fromIntegral b)
showSci (Sci(a,b)) = (show a)++"e"++(show b)
lx :: Double
lx = log 10
log10 :: Double -> Double
log10 y = log y / lx
-- ~ main = putStrLn $ showSci $ fixSci $ Sci(95,0)
main = putStrLn $ showSci $ mkSci 95
下面是一个示例错误:
sci.hs:5:40:
Could not deduce (a ~ Double)
from the context (Floating a, Integral b)
bound by the instance declaration at sci.hs:4:10-49
`a' is a rigid type variable bound by
the instance declaration at sci.hs:4:20
In the first argument of `(*)', namely `a'
In the expression: a * c
In the first argument of `Sci', namely `(a * c, b * d)'
sci.hs:5:44:
Could not deduce (b ~ Integer)
from the context (Floating a, Integral b)
bound by the instance declaration at sci.hs:4:10-49
`b' is a rigid type variable bound by
the instance declaration at sci.hs:4:31
In the first argument of `(*)', namely `b'
In the expression: b * d
In the first argument of `Sci', namely `(a * c, b * d)'
任何帮助都是非常感谢的!
发布于 2014-01-09 22:32:55
诚然,阅读和理解GHC错误消息并不容易。因此,你的问题是正确的。
显然,这些消息引用的是*
操作符的定义。我们可以从sci.hs:5:40
中提到的行号和(*)是您在Num实例中定义的唯一行号来判断这一点。
记住*
的一般类型,它是
(*) :: Num n => n -> n -> n
这意味着:对于所有具有Num实例的类型n,如果将该类型的2个值给*
,您将得到另一个相同类型的值。或者更简单的:(*
)可以适用于任何数字类型,只要这些因素是相同类型的,并且结果将具有与这些因素相同的类型。
不用说,您的*
实现必须履行此合同。由于您的Sci
类型本身是多态的,所以您的化身具有以下类型:
(*) :: (Floating a, Integral b) => Sci a b -> Sci a b -> Sci a b
因此,您声称您的乘法对于任何类型的a和b都适用于Sci a b
类型,只要a是浮动类型,b是Intergal类型。也就是说,它应该适用于Sci Float Int
,也适用于Sci Double Integer
。
到现在为止,您应该已经知道了错误是什么:您的实现没有实现该承诺。实际上,它只适用于Sci Double Integer
,因为您的助手函数fixSci
只能使用Sci Double Integer
。
错误消息试图以更技术性的形式告诉您这一点。它列出了
a
vs Double
(“你答应给我任何东西,但我得到的只是一个糟糕的双倍!”)a
是Floating
的一个实例)以及引入它的地方。Double
的表达式。不幸的是,编译器在有趣的部分之前停止(简洁,因为众所周知,新手从来不读取错误消息:)。它可能包括这样的东西
in the expression fixSci (Sci (a*c) (b*d)),
and since fixSci takes an argument of type Sci Double Integer
I concluded that Sci (a*c) (b*d) must be Sci Double Integer
and hence (a*c) must be Double.
发布于 2014-01-09 22:43:13
与您的问题无关,而是与代码有关:
真的应该是mulSci (Sci(a,b)) (Sci(c,d)) = fixSci (Sci(a*c,b*d))
吗?不是应该是b+d
而不是b*d
吗
你为什么不直接设置newtype Sci = Sci Double Integer
呢?那你就会
instance Num Sci where
(Sci m1 e1) * (Sci m2 e2) = fixSci (Sci (m1*m2) (e1+e2))
(Sci m1 e1) + (Sci m2 e2) = <some rather complicated expression>
发布于 2014-01-09 23:05:54
这不是你最初的问题,但你的showSci
函数困扰着我:
不要派生“显示”,编写自己的显示函数:
instance Show Sci where
show (Sci (a,b)) = (show a) ++ "e" ++ (show b)
然后main
变成:
main = print $ mkSci 95
https://stackoverflow.com/questions/21031522
复制相似问题