I have defined the following Functor with the following type class ...
-- Let's suppose we want to create a functor that
-- performs the opperation :
--
-- fmap inc (Strength 3)
data Stat a = Strength a | Agility a | Constitution a
deriving Show
instance Functor Stat where
-- fmap :: (a -> b) -> Stat a -> Stat b
fmap g (Strength str) = Strength (g str)
fmap g (Agility agi) = Agility (g agi)
fmap g (Constitution con) = Constitution (g con)
-- Then it can be called as fmap inc (Strength 3)
-- Let's suppose I use a Type class for this function
class Inc a where
incStat :: (Num a) => a -> a
instance Inc (Stat a) where
incStat (Strength a) = Strength a
-- instance Show a => Show (Stat a) where
-- show (Strength a) = show (a)
-- show (Agility a) = show (a)
-- show (Constitution a) = show (a)
It builds ok, but when I try to do the following command
fmap incStat (Strength 3)
I'm getting the following error I don´t fully understand
<interactive>:62:1: error:
• Ambiguous type variable ‘b0’ arising from a use of ‘print’
prevents the constraint ‘(Show b0)’ from being solved.
Probable fix: use a type annotation to specify what ‘b0’ should be.
Potentially matching instances:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show a => Show (Stat a)
-- Defined at characteristicsFunctor.hs:9:24
...plus 26 others
...plus 12 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it
Can you help me ? What is the error saying ?
NOTE : take IncStat as identity . I`m just checking the structure of the script
incStat
already understands your functor, it does not need fmap
to teach it how. So you may either use incStat
directly, without fmap
:
> incState (Strength 3)
Strength 3
or you may use fmap
directly, without incStat
:
> fmap (1+) (Strength 3)
Strength 4
To encapsulate this version you may like to define incStat
in terms of fmap
:
instance Num a => Inc (Stat a) where
incStat = fmap (1+)
If you insist on using both incStat
and fmap
, then you must have an outer functor for the fmap
to operate on -- which, if you like, may again be Stat
.
> fmap incStat [Strength 3, Strength 4]
[Strength 3, Strength 4]
> fmap incStat (Agility (Strength 3))
Agility (Strength 3)
As an aside, the Num
constraint in your Inc
declaration is almost certainly a mistake. I recommend deleting it.
class Inc a where incStat :: a -> a
The Num
constraints are better placed on the instances, where they are used.
instance Num a => Inc (Stat a) where
incState (Strength a) = Strength (1+a)