首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >重载操作符::HaskellNewbie

重载操作符::HaskellNewbie
EN

Stack Overflow用户
提问于 2014-01-09 21:27:23
回答 3查看 113关注 0票数 0

我正在做一种新的类型,这样我就能精确地计算出大的数字。基本上,表示数字为Double * 10 ^ Integer的是一个双整数和一个整数。现在我开始制作程序,它一直是"ok“,直到我尝试创建一个新数字的实例,这样我就可以简单地使用+来添加我的新数字了。这使我更容易在我现有的程序中使用。但我只是从我的代码中得到了一个类似于“无法推断”的错误(我将在下面发布一个示例)。我有点理解这个错误,但我似乎可以回避这个问题。如果希望编译代码,请注释第4和第5行。

我已经做了好几个小时了,我要“杀了”我。

代码语言:javascript
运行
复制
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

下面是一个示例错误:

代码语言:javascript
运行
复制
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)'

任何帮助都是非常感谢的!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-01-09 22:32:55

诚然,阅读和理解GHC错误消息并不容易。因此,你的问题是正确的。

显然,这些消息引用的是*操作符的定义。我们可以从sci.hs:5:40中提到的行号和(*)是您在Num实例中定义的唯一行号来判断这一点。

记住*的一般类型,它是

代码语言:javascript
运行
复制
(*) :: Num n => n -> n -> n

这意味着:对于所有具有Num实例的类型n,如果将该类型的2个值给*,您将得到另一个相同类型的值。或者更简单的:(*)可以适用于任何数字类型,只要这些因素是相同类型的,并且结果将具有与这些因素相同的类型。

不用说,您的*实现必须履行此合同。由于您的Sci类型本身是多态的,所以您的化身具有以下类型:

代码语言:javascript
运行
复制
(*) :: (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

错误消息试图以更技术性的形式告诉您这一点。它列出了

  1. 类型冲突a vs Double (“你答应给我任何东西,但我得到的只是一个糟糕的双倍!”)
  2. 实际范围内的约束(“您说过,aFloating的一个实例)以及引入它的地方。
  3. 导致编译器推断Double的表达式。

不幸的是,编译器在有趣的部分之前停止(简洁,因为众所周知,新手从来不读取错误消息:)。它可能包括这样的东西

代码语言:javascript
运行
复制
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.
票数 4
EN

Stack Overflow用户

发布于 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呢?那你就会

代码语言:javascript
运行
复制
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>
票数 0
EN

Stack Overflow用户

发布于 2014-01-09 23:05:54

这不是你最初的问题,但你的showSci函数困扰着我:

不要派生“显示”,编写自己的显示函数:

代码语言:javascript
运行
复制
instance Show Sci where
    show (Sci (a,b)) = (show a) ++ "e" ++ (show b) 

然后main变成:

代码语言:javascript
运行
复制
main = print $ mkSci 95
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21031522

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档