I'm trying to experiment with functors and safe division in Haskell, but I got this little error, and I can't really figure out why.
here goes my code :
module Main
where
data Failable a = Failure String | Success a
instance (Show a) => Show (Failable a) where
show (Failure s) = "Failure : " ++ s
show (Success x) = "Success : " ++ (show x)
instance Functor Failable where
fmap f (Success x) = Success (f x)
fmap _ (Failure s) = Failure s
(//) :: (Num a) => Failable a -> Failable a -> Failable a
_ // (Success 0) = Failure "Division by zero"
x // y = fmap (fmap (/) x) y
main = do
print $ (Success 1) // (Success 2)
And the output :
main.hs:16:16:
Couldn't match expected type ‘a -> a’
with actual type ‘Failable (a -> a)’
Relevant bindings include
y :: Failable a (bound at main.hs:16:6)
x :: Failable a (bound at main.hs:16:1)
(//) :: Failable a -> Failable a -> Failable a
(bound at main.hs:15:1)
Possible cause: ‘fmap’ is applied to too many arguments
In the first argument of ‘fmap’, namely ‘(fmap (/) x)’
In the expression: fmap (fmap (/) x) y
I think you are trying to lift (/)
to the Failable
functor.
You could achieve that using pattern matching, but I think you want to do it using the Functor
functions (fmap
), alone.
This is however impossible. At best, fmap (/)
can provide
(/) :: Num a => a -> a -> a
fmap (/) :: Num a => Failable a -> Failable (a -> a)
and we have no general way to turn that ugly Failable (a -> a)
into Failable a -> Failable a
.
This is why we have a more powerful type class: Applicative
, for doing precisely that
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
So... congratulations. You have just discovered the issue for which such a type class was introduced.
I'd recommend you write a Applicative
instance. After that, (omitting the zero check)
(//) = liftA2 (/)
-- or, (this being the most popular style, nowadays)
x // y = (/) <$> x <*> y
-- or,
x // y = fmap (/) x <*> y