我有以下代码:
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
但是,当我尝试在ghci
中导入此文件时,出现以下错误:
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", ....]}
请注意,这仅在拆分文件后发生;我以前有一些代码消耗了&#34; lexer&#34;在同一模块中,然后将其分开。
我需要提供哪些类型的注释才能使其正常工作?
答案 0 :(得分:3)
解决方案是注释:def :: LanguageDef st
。这会将s0
修改为String
,将m0
修复为Identity
。
这是一个......松散的解释。
让我们从外部选择类型。(这不一定是推理如何工作,但我们通常已经或者可以获得顶级绑定的类型。)def
的推断类型在错误消息:GenLanguageDef s0 u m0
。查看GenLanguageDef
的定义,因此identStart
的推断类型为ParsecT s0 u m0 Char
。
letter
的类型为Stream s m Char => ParsecT s u m Char
。使用identStart
类型统一,我们得到需要以某种方式满足的约束Stream s0 m0 Char
。
monomorphism restriction禁止编译器简单地将推断的约束浮动到def
类型。禁用限制后,def
会推断出类型Stream s0 m0 Char => GenLanguageDef s0 u m0
。消费者可以像在之前的单文件解决方案中那样修复类型变量。
或者,提供我建议的具体签名只需修复变量s0
和m0
。现在编译器可以直接满足类约束,因为它知道Identity
是Monad
并且有一个实例Monad m => Stream String m Char
。
(您会认为,因为emptyDef
的类型为LanguageDef st
,转换为GenLanguageDef String st Identity
,def
将具有该类型。啊,但您正在使用记录更新语法,允许更改类型变量。)
答案 1 :(得分:2)
使用pragma:
{-# LANGUAGE NoMonomorphismRestriction #-}