haskelltypeclassapplicative

Making instance of Applicative


Still not a hundred percent shure how to make instances of the more complex types. Have this:

data CouldBe a = Is a | Lost deriving (Show, Ord) 

Made an instance of Functor, using Maybe as an example:

instance Functor CouldBe where 
  fmap f (Is x) = Is (f x) 
  fmap f Lost   = Lost 

For doing something like this:

tupleCouldBe :: CouldBe a -> CouldBe b -> CouldBe (a,b)
tupleCouldBe x y = (,) <$> x <*> y

CouldBe needs to be an instance of Applicative, but how would you go about that? Sure I can look it up and copy it, but I want to learn the process behind it and finally end up with the instance declaration of CouldBe.


Solution

  • You just write it out, following the types:

    instance Applicative CouldBe where
       {- 
            Minimal complete definition:
              pure, ((<*>) | liftA2)
    
          pure :: a -> f a 
          pure :: a -> CouldBe a
    
          liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
          liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c 
       -}
        pure a = fa
            where
            fa = ....
    
        liftA2 abc fa fb = fc
            where
            fc = ....

    According to

    data CouldBe a = Is a | Lost
    

    our toolset is

    Is   :: a -> CouldBe a
    Lost :: CouldBe a
    

    but we can also use pattern matching, e.g.

    couldBe   is   lost  (Is a)    = is a
    couldBe   is   lost  (Lost)    = lost
    couldBe :: ? -> ? -> CouldBe a -> b
    couldBe :: ? -> b -> CouldBe a -> b
    couldBe :: (a -> b) -> b -> CouldBe a -> b
    

    So,

        -- pure :: a -> f a 
        pure :: a -> CouldBe a     
    

    matches up with

        Is   :: a -> CouldBe a
    

    so we define

        pure a = Is a
    

    Then, for liftA2, we follow the data cases:

        -- liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
        -- liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c
        liftA2 abc Lost    _     = ...
        liftA2 abc  _     Lost   = ...
        liftA2 abc (Is a) (Is b) = fc
            where
            c = abc a b
            fc = ....     -- create an `f c` from `c`: 
                          -- do we have a `c -> CouldBe c` ?
                          -- do we have an `a -> CouldBe a` ? (it's the same type)
    

    But in the first two cases we don't have an a or a b; so we have to come up with a CouldBe c out of nothing. We do have this tool in our toolset as well.

    Having completed all the missing pieces, we can substitute the expressions directly into the definitions, eliminating all the unneeded interim values / variables.