I want to make the data type Moneda
a instance of the Semigroup, and implement the associative operation as +
. I'm having difficulties understanding it properly.
The working solution I found, is the following:
data Moneda a = RON Double | EUR Double deriving (Show)
instance Num a => Num (Moneda a) where
(RON x) + (RON y) = RON (x + y)
(RON x) + (RON y) = RON (x + y)
instance Semigroup (Moneda a) where
(<>) = (+)
I couldn't understand why exactly the below aproach is failing and how it's possible to make it work without making Moneda
a Num
instance.
data Moneda a = RON a | EUR a deriving (Show)
instance Semigroup (Moneda a) where
(<>) (RON a) (RON b) = (RON a+b) -- fails, please see error below
vs
(<>) (RON a) (RON b) = (RON a) -- works but doesn't help me because I need the a+b sum
-- cannot construct the infinite type: a ~ Moneda a
-- In the second argument of `(+)', namely `b'
The error you're getting is because you try to add a value of type Moneda a
to a value of type a
in your implementation of (<>)
. That is you wrote (RON a+b)
which parses as (RON a) + b
(because function/constructor application binds stronger than addition). You probably meant to write RON (a + b)
as in:
data Moneda a = RON a | EUR a deriving (Show)
instance Semigroup (Moneda a) where
(<>) (RON a) (RON b) = RON (a + b)
But that won't work either as it requires addition to be defined on the type to which you apply Moneda
. So, for your definition to make sense you will need to constrain the instantiation of the type argument a
to types in Num
:
data Moneda a = RON a | EUR a deriving (Show)
instance Num a => Semigroup (Moneda a) where
RON a <> RON b = RON (a + b)
EUR a <> EUR b = EUR (a + b)
For example:
> RON 2 <> RON 3
RON 5
Note that this definition of (<>)
is only partial. It does not account for adding values built with RON
to values built with EUR
:
> RON 5 <> EUR 7
*** Exception: Main.hs:(4,3)-(5,30): Non-exhaustive patterns in function <>
So, you still have to write code that deals with those cases.