0

I'm making a new type so I can calculate big numbers with some precision. Basically its a Double and a Integer to represent a number as Double * 10 ^ Integer. Now I began to make the program and it was going "ok" till I tried to make a instance of my new number so I could simple use + to add my new numbers up. This makes it easier for me to use in my existing programs. But I'm just getting a errors along the lines of "Could not deduce" from my code (I'll post an example below). I somewhat understand the error, but I can seem to get around the problem. If you wish to compile the code, comment lines 4 and 5.

I'v been working on this for hours and is "killing" me.

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

Here is an example error:

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)'

Any help is much appreciated!

8
  • 1
    "But I'm just getting a errors from my code." Have you tried reading the errors, and reducing the problem to its core? Note that both errors refer to line 5. Commented Jan 9, 2014 at 21:33
  • It would also help if you posted the errors that you're getting. I can see one immediate problem where you've neglected to implement the minimum complete definition of the Num typeclass. You also need +, - or negate, abs, and signum (I think that's all, but check the docs to be sure) Commented Jan 9, 2014 at 21:36
  • Would the scientific package be useful instead? Commented Jan 9, 2014 at 21:39
  • "I am getting errors.", "It doesn't work." and phrases like this are no actual problem descriptions. Indeed, if it were, we could reduce 95% of all SO postings to the following "I wrote something in some language I am a newbie in, but it doesn't work." Commented Jan 9, 2014 at 21:44
  • 1
    Fwiw, (Int64, Int64) seems cleaner than (Double, Integer) to store your components Commented Jan 10, 2014 at 3:41

3 Answers 3

4

Admittedly, reading and understanding GHC error messages is not easy. Therefore, your question is valid.

Obviously, the messages are referring to your definition of the * operator. We can tell this from the line number mentioned in sci.hs:5:40 and from the fact that (*) is the only one you defined in your Num instance.

Remember the general type of *, it is

(*) :: Num n => n -> n -> n

which means: For all types n that have a Num instance, if you give 2 values of that type to *, you will get back another value of same type. Or simpler: (*) will work for any numeric type, as long as the factors are of the same type and the result will have the same type as the factors.

Needless to say, your implementation of * must fulfill this contract. And because your Sci type itself is polymorphic, your incarnation has the type:

(*) :: (Floating a, Integral b) => Sci a b -> Sci a b -> Sci a b

So your are claiming that your multiplication will work for type Sci a b for any types a and b, as long as a is a Floating type and b is an Intergal type. That is, it should work for Sci Float Int as well as for Sci Double Integer.

By now, you should already know what the error is: Your implementation doesn't live up to that promise. In fact, it only works for Sci Double Integer, because your helper function fixSci can only work with Sci Double Integer.

The error message tries to tell you just that, in a more technical form. It lists

  1. the type conflict a vs Double ("You promised to give me anything, but all I got was a lousy Double!")
  2. the constraints actually in scope ("You said, a was an instance of Floating) and where it was introduced.
  3. The expression(s) that led the compiler to infer Double

Unfortunately, the compiler stops short (for brevity, as it is known that newbies never read error messages anyway :) before the interesting part. It could have included something like

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.
Sign up to request clarification or add additional context in comments.

1 Comment

This is very nice, thanks for the response, I only vaguely understood the other similar problems on SO. Sometime the other responses were rather intimidating.
0

Not really related to your question, but to your code:

Should it really be mulSci (Sci(a,b)) (Sci(c,d)) = fixSci (Sci(a*c,b*d))? Shouldn't it be b+d instead of b*d?

Why don't you just set newtype Sci = Sci Double Integer? Then you would have

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>

3 Comments

You would need data here, or leave the tuple.
Oh... Yes, you're right, newtype can only wrap one type (though it may be a composite type), not several as in my code.
Thanks, this was a good example of how my could should have looked. I based my solution off of this. Yeah, that's one of several mistakes in my code, ill fix it up for others future reference.
0

Not your original question, but your showSci function bothers me:

Don't derive Show, write your own show function:

instance Show Sci where
    show (Sci (a,b)) = (show a) ++ "e" ++ (show b) 

Then main becomes:

main = print $ mkSci 95

1 Comment

I derived show because I wanted a raw view of a Sci type, I also didn't know how to do what you said above. I plan on making a show function that looks like how a float is printed. Thanks for the tip

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.