8.6. Basic monadic Happy use with Alex

Alex lexers are often used by Happy parsers, for example in GHC. While many of these applications are quite sophisticated, it is still quite useful to combine the basic Happy %monad directive with the Alex monad wrapper. By using monads for both, the resulting parser and lexer can handle errors far more gracefully than by throwing an exception.

The most straightforward way to use a monadic Alex lexer is to simply use the Alex monad as the Happy monad:

Example 8.1. Lexer.x

{
module Lexer where
}

%wrapper "monad"

tokens :-
  ...

{
data Token = ... | EOF
  deriving (Eq, Show)

alexEOF = return EOF
}

Example 8.2. Parser.y

{
module Parser where

import Lexer
}

%name pFoo
%tokentype { Token }
%error { parseError }
%monad { Alex } { >>= } { return }
%lexer { lexer } { EOF }

%token
  ...

%%
  ...

parseError :: Token -> Alex a
parseError _ = do
  ((AlexPn _ line column), _, _, _) <- alexGetInput
  alexError ("parse error at line " ++ (show line) ++ ", column " ++ (show column))

lexer :: (Token -> Alex a) -> Alex a
lexer = (alexMonadScan >>=)
}

We can then run the finished parser in the Alex monad using runAlex, which returns an Either value rather than throwing an exception in case of a parse or lexical error:

import qualified Lexer as Lexer
import qualified Parser as Parser

parseFoo :: String -> Either String Foo
parseFoo s = Lexer.runAlex s Parser.pFoo