Search code examples
haskellapplicative

Applicative for a user defined type


I'm trying to write Applicative for this type

data Choice a = ColumnA a | ColumnB a

I wrote a Functor instance:

instance Functor Choice where 
  fmap f (ColumnA a ) = (ColumnA (f a) )
  fmap f (ColumnB a ) = (ColumnB (f a) ) 

Now I want to write Applicative where ColumnB is considered "a correct value" and ColumnA is considered to be some kind of an error.

I tried

instance Applicative Choice where
    pure             =  ColumnB  
    ColumnB f  <*>  r  =  fmap f r
    ColumnA f  <*>  _  =  ColumnA  f   --- this does not work 

How can I make it work ?


Solution

  • Let's rename your data constructors to express your intent properly, as

    data Choice a = Bad a | Good a
    

    Your Functor instance keeps the taint on the values,

    instance Functor Choice where 
      fmap f (Bad  x)  =  Bad  (f x) 
      fmap f (Good x)  =  Good (f x) 
    

    so let's just do the same for the Applicative, without being skimpy with our clauses:

    instance Applicative Choice where
        pure              x  =  Good    x     -- fmap f == (pure f <*>) is the Law
        Good f  <*>  Good x  =  Good (f x)
        Good f  <*>  Bad  x  =  Bad  (f x)
        Bad  f  <*>  Good x  =  Bad  (f x)
        Bad  f  <*>  Bad  x  =  Bad  (f x)
    

    As was pointed in the comments, this interprets Choice a as isomorphic to Writer All a, meaning, Choice a values are really just like (Bool, a) with (False, x) corresponding to Bad x and (True, x) corresponding to Good x. Naturally we only consider values to be Good if everything in their provenance was Good as well.