5.4. Type Signatures and Typeclasses

The %token, %typeclass, and %action directives can be used to cause Alex to emit additional type signatures in generated code. This allows the use of typeclasses in generated lexers.

5.4.1. Generating Type Signatures with Wrappers

The %token directive can be used to specify the token type when any kind of %wrapper directive has been given. Whenever %token is used, the %typeclass directive can also be used to specify one or more typeclass constraints. The following shows a simple lexer that makes use of this to interpret the meaning of tokens using the Read typeclass:

%wrapper "basic"
%token "Token s"
%typeclass "Read s"

tokens :-

[a-zA-Z0-9]+ { mkToken }
[ \t\r\n]+   ;

{

data Token s = Tok s

mkToken :: Read s => String -> Token s
mkToken = Tok . read

lex :: Read s => String -> [Token s]
lex = alexScanTokens

}

Multiple typeclasses can be given by separating them with commas, for example:

%typeclass "Read s, Eq s"

5.4.2. Generating Type Signatures without Wrappers

Type signatures can also be generated for lexers that do not use any wrapper. Instead of the %token directive, the %action directive is used to specify the type of a lexer action. The %typeclass directive can be used to specify the typeclass in the same way as with a wrapper. The following example shows the use of typeclasses with a "homegrown" monadic lexer:

{
{-# LANGUAGE FlexibleContexts #-}

module Lexer where

import Control.Monad.State
import qualified Data.Bits
import Data.Word

}

%action "AlexInput -> Int -> m (Token s)"
%typeclass "Read s, MonadState AlexState m"

tokens :-

[a-zA-Z0-9]+ { mkToken }
[ \t\n\r]+   ;

{

alexEOF :: MonadState AlexState m => m (Token s)
alexEOF = return EOF

mkToken :: (Read s, MonadState AlexState m) =>
           AlexInput -> Int -> m (Token s)
mkToken (_, _, _, s) len = return (Tok (read (take len s)))

data Token s = Tok s | EOF

lex :: (MonadState AlexState m, Read s) => String -> m (Token s)
lex input = alexMonadScan

-- "Boilerplate" code from monad wrapper has been omitted

}

The %token directive may only be used with wrapper, and the %action can only be used when no wrapper is used.

The %typeclass directive cannot be given without the %token or %action directive.