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 ?
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.