0
votes
data Tick = Tick
  { _price :: Int
  , _timestamp :: TimeOfDay
  } deriving (Eq, Ord)

instance Num Tick where
  (-) (Tick a b) (Tick a' _) = Tick (a - a') b


calcAxis :: High -> Low -> Int
calcAxis (Just (Tick a _)) (Just (Tick b _)) = (fromIntegral (a - b)) / 2

I understand dividing Int's will produce a Float, so I need to cast the Int's using fromIntegral before using (/) however I still get error:

• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: (fromIntegral (a - b)) / 2
  In an equation for ‘calcAxis’:
      calcAxis (Just (Tick a _)) (Just (Tick b _))
        = (fromIntegral (a - b)) / 2

I dont really understand what its asking me to do. Surely I don't have to define an instance for Fractional Int?

I assume I'm doing something wrong.

2
If I understand correctly, the error message is complaining about the entire expression (fromIntegral (a - b)) / 2 — this is Fractional, but you've asked (via the type signature of calcAxis) for it to be Int.ShreevatsaR
If I remove the division and update the signature for calcAxis to return a Float it typechecks ok.ktec
@Globalkeith: Why would you do both? Update the signature to return a Float and don’t remove the division.Ry-
Doh, ignore me - it typechecks when it returns a Float!! thanksktec
Yes, it's probably the right thing to just keep the result a fractional type. Though Float is pretty unusual in Haskell, normally the higher-precision Double or exact Rational are prefered.leftaroundabout

2 Answers

3
votes

The problem is that you end up with a float after using / and your type spec says you should be returning an Int.

You need to either round/truncate convert to Int or change the type signature of calcAxis.

> let a = 1 :: Int
> let b = 2 :: Int
> let c = (fromIntegral (a - b)) / 2
> :t c
c :: Fractional a => a

And there's no instance for Fractional Int is what the type error is indicating.

3
votes

As Ryan commented, it's probably the right thing to just keep the result a fractional type. Float is pretty unusual in Haskell though, normally the higher-precision Double or exact Rational are prefered.

calcAxis :: High -> Low -> Double
calcAxis (Just (Tick a _)) (Just (Tick b _)) = fromIntegral (a - b) / 2
calcAxis _ _ = ... -- keep in mind to handle the `Nothing` case as well!

That said, if you have a reason to make the result Int, and always want to round towards zero, that can be done simply with integer division:

calcAxis :: High -> Low -> Int
calcAxis (Just (Tick a _)) (Just (Tick b _)) = (a - b) `quot` 2

...or, if you always want to round down,

calcAxis (Just (Tick a _)) (Just (Tick b _)) = (a - b) `div` 2