5.4. Type Signatures and Typeclasses
Prev | Chapter 5. The Interface to an Alex-generated lexer | Next

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

Prev | Up | Next
5.3. Wrappers | Home | Chapter 6. Invoking Alex