Reputation: 539
I am currently trying to understand Haskell Type-Classes. After creating the simple example below and seeing that it works ....
data MyMaybe a = MyNothing | MyJust a
deriving(Show)
class IncreaseByOne a where
addOne :: a -> a
instance (Num a) => IncreaseByOne (MyMaybe a) where
addOne MyNothing = (MyNothing)
addOne (MyJust x) = (MyJust (x+1))
asked my self: Is it possible to add the function addOne to the existing Type-Class Num. So all Numbers can make use of the function addOne. Something like:
instance IncreaseByOne Num where
addOne x = x+1
Upvotes: 0
Views: 717
Reputation: 70287
It's also worth noting that you can just define a free-standing function. Unlike in Java or C#, where free functions (erm, static
functions) are different and are called differently than instance functions, in Haskell there's really no difference. So, if all you want to do is make a function that works for all Num
, here it is.
addOne :: Num a => a -> a
addOne = (+1)
No typeclasses necessary. That type signature literally reads as "for all numbers a
, takes an a
and returns an a
".
Upvotes: 3
Reputation: 120711
Well, you can in principle write instances like
{-# LANGUAGE UndecidableInstances #-}
instance (Num a) => IncreaseByOne a where
addOne x = x+1 -- or `addOne = (+1)`
The -XUndecidableInstances
is not really a problem, but what's a problem is that this instance overlaps with any other instances you might want to declare, specifically with your MyMaybe
one. The reason there's a problem there is that nothing in principle stops you from also having, maybe only later on in a module further downstream,
instance Num a => Num (MyMaybe a) where ...
and then both the Num a => IncreaseByOne a
and Num a => IncreaseByOne (MyMaybe a)
would apply.
GHC can do overlapping instances, but it's usually a bad idea. I would suggest you instead just write out short instances for all the concrete types that are relevant. To make this extra concise, you can have a default implementation based on Num
:
{-# LANGUAGE DefaultSignatures #-}
class IncreaseByOne a where
addOne :: a -> a
default addOne :: Num a => a -> a
addOne = (+1)
instance (Num a) => IncreaseByOne (MyMaybe a) where
addOne = fmap (+1) -- `MyMaybe` _should_ have a `Functor` instance!
instance IncreaseByOne Int -- note no instance body is needed,
instance IncreaseByOne Integer -- because the default implementation
instance IncreaseByOne Double -- applies
Upvotes: 6