Reputation: 7674
I am relatively new to learning haskell.
I have the following abstract data type
data Scalar =
Scalar Integer
deriving (Eq, Show)
I want to be able to do the following operation on the Scaler type:
> (Scalar 10) + 1
> Scalar 11
To do this I tried making the Scalar
an instance of the num
class like this:
instance Num Scalar where
(Scalar i1) + i2 = (Scalar (i1+i2))
But this doesn't work. What am I doing wrong? And whats the correct way to do this?
Edit: The error I am getting is:
Couldn't match expected type `Integer' with actual type `Scalar ' In the second argument of `(+)', namely `i2' In the first argument of `Scalar ', namely `(i1 + i2)'
Upvotes: 1
Views: 9323
Reputation: 226
As others have already pointed out the types on both sides of +
need to match. What you can do is define a custom operator to add Scalar
and Int
:
(+.) :: Scalar -> Int -> Scalar
(Scalar i1) +. i2 = Scalar (i1 + i2)
infixl 6 +.
You might also want to use a newtype
wrapper instead (all you have to do is replace the data
keyword with newtype
). This is semantically the same (except in some corner cases with undefined values) but slightly more efficient because newtypes are erased during compilation.
Upvotes: 0
Reputation: 48766
No, you cannot do that, because the type of +
is:
λ> :t (+)
(+) :: Num a => a -> a -> a
So, it operates on the type of same data. In your case you are trying to add a type of Scalar
and Integer
which isn't valid. You can define an instance like this:
instance Num Scalar where
(Scalar i1) + (Scalar i2) = Scalar (i1 + i2)
And it will operate on Scalar
type:
λ> Scalar 3 + Scalar 4
Scalar 7
But if you really want to do this, you can create your own special function for that:
addNumtoScalar :: Integer -> Scalar -> Scalar
addNumtoScalar x (Scalar y) = Scalar (x + y)
And then you can add using this function,
λ> addNumtoScalar 3 (Scalar 7)
Scalar 10
Or in an infix fashion:
λ> 3 `addNumtoScalar` (Scalar 7)
Scalar 10
As @user5402 has commented, you can define the fromInteger
function of Num
typeclass and then use that in your addition. Something like this:
instance Num Scalar where
(Scalar x) + (Scalar y) = Scalar (x + y)
fromInteger x = Scalar x
Now, you can use integer literals and they will be automatically converted to Scalar
values when necessary, e.g.:
λ> 3 + Scalar 7
Scalar 10
Upvotes: 9
Reputation: 7705
You can't add a Scalar
and an Integer
(e.g. Scalar 10 + 1
); you should wrap the second value in a Scalar before adding. Thus, your instance should look like this:
instance Num Scalar where
(Scalar i1) + (Scalar i2) = (Scalar (i1+i2))
However, the Num
typeclass provides requires several other methods besides +
be implemented. Instead of writing all that manually, you can use the GHC GeneralizedNewtypeDeriving extension to handle all that for you:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Scalar = Scalar Integer deriving (Eq,Show,Num)
This will automatically derive the Num
instance for Scalar
based on how Integer
implements the Num
typeclass. This approach requires you to use a newtype, but it sounds like that's appropriate for your usecase.
Upvotes: 2
Reputation: 833
Firstly, there's something wrong with your definition:
(Scalar i1) + i2 = (Scalar (i1+i2))
That should be the following:
(Scalar i1) + (Scalar i2) = Scalar (i1+i2)
Secondly, if you look at the documentation of the Num
typeclass
You will see the part about the minimal complete definition.
(+), (*), abs, signum, fromInteger, (negate | (-))
You've implemented (+)
, but none of the others.
Lastsly, if you post a problem, include the error that you're getting please.
Good luck
Upvotes: 1