12

To help me learn Applicative Functors and Functors I thought it would be good fun to see how Either is implemented with the typeclasses Functor and Applicative. Obviously I could just go ahead and read the code but I find it more useful to try and implement things myself to get a better understanding of things.

FYI I'm trying to implement the Haskell version of the results of this presentation http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/chunk-html/index.html

Anyway, this is what I have so far

 data Validation a b = Success a | Failure b deriving (Show, Eq)

 instance Functor (Validation a) where
     fmap f (Failure x) = Failure x
     fmap f (Success x) = Success (f x)

But whenever I try to run this with ghci I just get the following error message: -

[1 of 1] Compiling Main             ( t.hs, interpreted )

t.hs:5:35:
    Couldn't match type `b' with `a1'
      `b' is a rigid type variable bound by
          the type signature for
            fmap :: (a1 -> b) -> Validation a a1 -> Validation a b
          at t.hs:4:5
      `a1' is a rigid type variable bound by
           the type signature for
             fmap :: (a1 -> b) -> Validation a a1 -> Validation a b
           at t.hs:4:5
    Expected type: a
      Actual type: b
    In the return type of a call of `f'
    In the first argument of `Success', namely `(f x)'
    In the expression: Success (f x)

t.hs:5:37:
    Couldn't match type `a' with `a1'
      `a' is a rigid type variable bound by
          the instance declaration at t.hs:3:30
      `a1' is a rigid type variable bound by
           the type signature for
             fmap :: (a1 -> b) -> Validation a a1 -> Validation a b
           at t.hs:4:5
    In the first argument of `f', namely `x'
    In the first argument of `Success', namely `(f x)'
    In the expression: Success

I'm not really sure why this is, can anyone help?

djhworld
  • 6,726
  • 4
  • 30
  • 44

1 Answers1

13

You're trying to make the Functor instance work on the Success part, which is the normal thing to do, but because of the order of your type parameters it is being defined on the type in the Failure part instead.

Since you've defined it as

data Validation a b = Success a | Failure b

instance Functor (Validation a) where
    ...

This means that your implementation of fmap should have the type (x -> y) -> Validation a x -> Validation a y. But since the second type variable is for the Failure case, this does not type check.

You want the type variable for the Success case to be the last one instead:

data Validation b a = Success a | Failure b
hammar
  • 138,522
  • 17
  • 304
  • 385
  • Ahhh I see, thanks, I'm presuming `data Validation a b = Failure a | Success b deriving (Show, Eq)` would also be correct. Thanks! – djhworld Aug 19 '11 at 12:15
  • 1
    @djworld: Yep. That's just the same thing with the names of the type variables and the order of the constructors swapped. – hammar Aug 19 '11 at 12:19
  • 5
    @djhworld: And now you also understand why, in `Either a b`, `Left` represents the failure case (not just because it isn't the "right" result). – C. A. McCann Aug 19 '11 at 12:43