Type input error while defining lexer using makeTokenParser

I have the following code:

module Lexer (lexer) where                                                                                                                                                                                                
import Text.Parsec                                                                                                                                                                                                        
import Text.Parsec.Token                                                                                                                                                                                                  
import Text.Parsec.Language                                                                                                                                                                                               

opChars = "<>+=*-/!:"                                                                                                                                                                                                     

def = emptyDef {                                                                                                                                                                                                          
    commentStart = "/*"                                                                                                                                                                                                   
  , commentEnd = "*/"                                                                                                                                                                                                     
  , identStart = letter                                                                                                                                                                                                   
  , identLetter = alphaNum                                                                                                                                                                                                
  , opStart = oneOf opChars                                                                                                                                                                                               
  , opLetter = oneOf opChars                                                                                                                                                                                              
  , reservedOpNames = ["+", "-", "*", "!=", "==", ":=", "<", "<=", ">", ">="]                                                                                                                                             
  , reservedNames = ["and", "not", "or", "p_", "when", "output", "of"]                                                                                                                                                    
  }

lexer = makeTokenParser def                                                                                                                                                                                               

      

However, when I try to import this file into ghci

, I get the following error:

Prelude> :l Lexer.hs
[1 of 1] Compiling Lexer            ( Lexer.hs, interpreted )

Lexer.hs:11:18:
    No instance for (Stream s0 m0 Char) arising from a use of `letter'
    The type variables `s0', `m0' are ambiguous
    Relevant bindings include
      def :: GenLanguageDef s0 u m0 (bound at Lexer.hs:8:1)
    Note: there are several potential instances:
      instance Monad m =>
               Stream Data.ByteString.Internal.ByteString m Char
        -- Defined in `Text.Parsec.Prim'
      instance Monad m =>
               Stream Data.ByteString.Lazy.Internal.ByteString m Char
        -- Defined in `Text.Parsec.Prim'
      instance Monad m => Stream Data.Text.Internal.Lazy.Text m Char
        -- Defined in `Text.Parsec.Prim'
      ...plus two others
    In the `identStart' field of a record
    In the expression:
      emptyDef
        {commentStart = "/*", commentEnd = "*/", identStart = letter,
         identLetter = alphaNum, opStart = oneOf opChars,
         opLetter = oneOf opChars, reservedOpNames = ["+", "-", "*", ....],
         reservedNames = ["and", "not", "or", ....]}
    In an equation for `def':
        def
          = emptyDef
              {commentStart = "/*", commentEnd = "*/", identStart = letter,
               identLetter = alphaNum, opStart = oneOf opChars,
               opLetter = oneOf opChars, reservedOpNames = ["+", "-", ....],
               reservedNames = ["and", "not", ....]}

      

Note that this only happened after splitting the file; I previously had some code that was consuming "lexer" in the same module and then stripping it off.

What type annotations should I provide for this to work?

+3


source to share


2 answers


The solution is in the summary: def :: LanguageDef st

. This will fix from s0

to String

and m0

from Identity

.

Here's ... a free explanation.

Let's choose types from outside in. (This is not necessarily how the conclusion, but we usually have, or can get a top-level types of bindings.) Derived type of def

marked in the error message: GenLanguageDef s0 u m0

. Considering the definition GenLanguageDef

, the inferred type identStart

is therefore ParsecT s0 u m0 Char

.

letter

has a type Stream s m Char => ParsecT s u m Char

. Combining this with the type identStart

, we end up with a constraint Stream s0 m0 Char

that must be met in some way.



The monomorphism constraint prevents the compiler from simply floating an inferred type constraint def

. When the constraint def

is disabled, has an inferred type Stream s0 m0 Char => GenLanguageDef s0 u m0

. The consumer can fix the type variables as in the previous single-file solution.

Alternatively, by providing a specific signature, I suggested simply fixing the variables s0

and m0

. Now the compiler can directly bind the class constraint since it knows what Identity

is Monad

and what an instance exists Monad m => Stream String m Char

.

(You might think that because it emptyDef

has a type LanguageDef st

that translates to GenLanguageDef String st Identity

, it def

will have that type. Ah, but you're using a record update syntax that allows type variables to change.)

+3


source


Use pragma:



{-# LANGUAGE NoMonomorphismRestriction #-}

      

+2


source







All Articles