1

我正在尝试熟悉 Haskell 的快乐解析器生成器。目前,我有一个来自文档的示例,但是当我编译程序时,出现错误。这是代码:

{
module Main where
import Data.Char
}

%name calc
%tokentype { Token }
%error { parseError }

%token 
      let             { TokenLet }
      in              { TokenIn }
      int             { TokenInt $$ }
      var             { TokenVar $$ }
      '='             { TokenEq }
      '+'             { TokenPlus }
      '-'             { TokenMinus }
      '*'             { TokenTimes }
      '/'             { TokenDiv }
      '('             { TokenOB }
      ')'             { TokenCB }

%%

Exp   : let var '=' Exp in Exp  { \p -> $6 (($2,$4 p):p) }
      | Exp1                    { $1 }

Exp1  : Exp1 '+' Term           { \p -> $1 p + $3 p }
      | Exp1 '-' Term           { \p -> $1 p - $3 p }
      | Term                    { $1 }

Term  : Term '*' Factor         { \p -> $1 p * $3 p }
      | Term '/' Factor         { \p -> $1 p `div` $3 p }
      | Factor                  { $1 }

Factor                    
      : int                     { \p -> $1 }
      | var                     { \p -> case lookup $1 p of
                                    Nothing -> error "no var"
                                    Just i  -> i }
      | '(' Exp ')'             { $2 }

{
parseError :: [Token] -> a
parseError _ = error "Parse error"

data Token
      = TokenLet
      | TokenIn
      | TokenInt Int
      | TokenVar String
      | TokenEq
      | TokenPlus
      | TokenMinus
      | TokenTimes
      | TokenDiv
      | TokenOB
      | TokenCB
 deriving Show

lexer :: String -> [Token]
lexer [] = []
lexer (c:cs) 
      | isSpace c = lexer cs
      | isAlpha c = lexVar (c:cs)
      | isDigit c = lexNum (c:cs)
lexer ('=':cs) = TokenEq : lexer cs
lexer ('+':cs) = TokenPlus : lexer cs
lexer ('-':cs) = TokenMinus : lexer cs
lexer ('*':cs) = TokenTimes : lexer cs
lexer ('/':cs) = TokenDiv : lexer cs
lexer ('(':cs) = TokenOB : lexer cs
lexer (')':cs) = TokenCB : lexer cs

lexNum cs = TokenInt (read num) : lexer rest
      where (num,rest) = span isDigit cs

lexVar cs =
   case span isAlpha cs of
      ("let",rest) -> TokenLet : lexer rest
      ("in",rest)  -> TokenIn : lexer rest
      (var,rest)   -> TokenVar var : lexer rest

main = getContents >>= print . calc . lexer
}

我收到此错误:

[1 of 1] Compiling Main             ( gr.hs, gr.o )

gr.hs:310:24:
No instance for (Show ([(String, Int)] -> Int))
  arising from a use of `print'
Possible fix:
  add an instance declaration for (Show ([(String, Int)] -> Int))
In the first argument of `(.)', namely `print'
In the second argument of `(>>=)', namely `print . calc . lexer'
In the expression: getContents >>= print . calc . lexer

你知道为什么以及如何解决它吗?

4

1 回答 1

6

如果您检查错误消息

No instance for (Show ([(String, Int)] -> Int))
  arising from a use of `print'

很明显,问题在于你正在尝试print一个函数。实际上,解析器函数产生的值calc应该是一个函数,它获取变量绑定的查找表并返回结果。例如,参见变量规则:

{ \p -> case lookup $1 p of
    Nothing -> error "no var"
    Just i  -> i }

所以在 中main,我们需要为p参数传入一个列表,例如一个空列表。(或者,如果需要,您可以添加一些预定义的全局变量)。我已将无点代码扩展为一个do块,以便更容易看到发生了什么:

main = do
  input <- getContents
  let fn = calc $ lexer input
  print $ fn [] -- or e.g. [("foo", 42)] if you wanted it pre-defined

现在它起作用了:

$ happy Calc.y
$ runghc Calc.hs <<< "let x = 1337 in x * 2"
2674
于 2013-05-27T18:44:16.087 回答