listhaskellconcatenationmonadsalternative-functor

Understanding function with <|> operator


I have the following type:

newtype Rep f a = Rep { runRep :: String -> f (String, a) }

The type Rep f a is a stateful computation that takes a String as the initial state and produces a (String, a) as the result of the computation. The result of the computation is wrapped in the functor f.

The Applicative instance for Rep is the following:

instance Monad f => Applicative (Rep f) where 
    pure x = Rep $ \s -> pure (s, x)
    Rep f <*> Rep x = Rep $ \s -> do 
        (s',rf)  <- f s 
        (s'',rx) <- x s'
        return (s'', rf rx)

And the Monad instance for Rep is the following:

instance Monad f => Monad (Rep f) where 
   return x = pure x 
   Rep a >>= f = Rep $ \s -> do
      (s', ya) <- a s
      let (Rep f') = f ya
      (s'', yf) <- f' s'
      pure (s'', yf)

The Alternative instance for Rep is the following:

instance (Monad f, Alternative f) => Alternative (Rep f) where 
    empty = Rep (const empty)
    Rep a <|> Rep b = Rep $ \s -> a s <|> b s

I have the following data types and function:

data TD = Empty | Fol TD TD | Letters [Char] | Str TD
data Res = Nil | Character Char | Cop Res Res | Special [Res]

findmatch :: (Monad f, Alternative f) => TD -> Rep f Res

findmatch (Str a) =
   frontAdd <$> findmatch a <*> findmatch (Str a)
   <|> pure (Special [])
      where
      frontAdd x (Special xs) = Special (x:xs)
      frontAdd _ _ = error "Not possible."

I am having trouble understanding the function above. The function frontAdd creates a Special value which contains a list of [Res]. findmatch returns Rep f Res. The line frontAdd <$> findmatch a <*> findmatch (Str a) applies frontAdd to the Res that is returned by findmatch a and findmatch (Str a).

However, I am not sure how this line, with the pattern matching, works: frontAdd x (Special xs) = Special (x:xs). Further, assuming that the functor f is [ ], how would the <|> in frontAdd <$> findmatch a <*> findmatch (Str a) <|> pure (Special []) work? I know that if the functor f is Maybe, then <|> makes a left-biased choice, but I don't know how <|> works specifically for lists. In the documentation it states:

instance Alternative [] where
  empty = []
  (<|>) = (++) -- length xs + length ys = length (xs ++ ys)

How exactly does the concatenation work? Am I correct in saying that the result of frontAdd <$> findmatch a <*> findmatch (Str a) is concatenated with the empty list?

Any insights are appreciated.


Solution

  • First, if f is [], then pure (Special []) is [(Special [])], which is just [Special []].

    Second, list concatenation is the most natural thing, with

      [a, b, c, d, ...]  ++  [p, q, r, s, ...]
    ==
      [a, b, c, d, ...   ,    p, q, r, s, ...]
    

    i.e.

    (x:xs) ++ ys  =  x : (xs ++ ys)
    []     ++ ys  =             ys
    

    which is to say,

       xs  ++ ys  =  foldr (:) ys xs
    

    Thus

      [a, b, c]  <|>  [Special []]
    ==
      [a, b, c,        Special []]
    

    and

      []         <|>  [Special []]
    ==
      [                Special []]
    

    So no, <|> pure (Special []) does not concatenate with the empty list, but rather with a list of a Special wrapping the empty list.