You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中chainl1与中缀操作符结合使用的异常问题咨询

问题分析与解决

首先明确代码的核心问题:

  • 符号匹配错误:pOper里的symbol "\"+\""是匹配带双引号的"+"字符串,但输入"2+2"里的+没有引号,导致运算符完全匹配失败,解析器返回空列表[]。
  • 你担心的匿名函数类型问题其实不成立:(\e1 e2 -> Not (Oper Eq e1 e2))的类型确实是Exp -> Exp -> Exp,符合pOper的类型签名——因为Not Exp属于Exp类型,这个匿名函数接收两个Exp参数并返回一个Exp,类型完全合法。

以下是保留pOper类型签名、不修改类型定义的修复方案,重点修正符号匹配逻辑并优化空格处理:

import Data.Char
import Text.ParserCombinators.ReadP
import Control.Applicative ((<|>))

type Parser a = ReadP a 

data Value =
  IntVal Int
  deriving (Eq, Show, Read)

data Exp =
    Const Value
  | Oper Op Exp Exp
  | Not Exp
  deriving (Eq, Show, Read)

data Op = Plus | Minus | Eq
  deriving (Eq, Show, Read)

space :: Parser Char
space = satisfy isSpace

spaces :: Parser String 
spaces = many space

space1 :: Parser String
space1 = many1 space

symbol :: String -> Parser String
symbol = token . string

-- 优化token:解析前后都跳过空格,自动处理运算符前后的空白
token :: Parser a -> Parser a
token combinator = do
  spaces
  result <- combinator
  spaces
  return result

parseString input = readP_to_S (do
                        e <- pExpr 
                        token eof
                        return e) input

pExpr :: Parser Exp 
pExpr = chainl1 pTerm pOper 

-- 简化pTerm:numConst已包含空格处理,无需重复逻辑
pTerm :: Parser Exp 
pTerm = numConst  

numConst :: Parser Exp
numConst = do  
  skipSpaces
  y <- munch isDigit            
  return (Const (IntVal (read y)))

-- 修改运算符匹配逻辑:去掉符号的引号,直接匹配裸运算符
pOper :: ReadP (Exp -> Exp -> Exp)
pOper = symbol "+" >> return (Oper Plus)
   <|> symbol "-" >> return (Oper Minus)
   <|> symbol "=" >> return (Oper Eq)
   <|> symbol "!=" >> return (\e1 e2 -> Not (Oper Eq e1 e2))

测试验证:

  • 输入parseString "2+2"会返回[(Oper Plus (Const (IntVal 2)) (Const (IntVal 2)), "")],符合预期。
  • 输入parseString "2!=3"会返回[(Not (Oper Eq (Const (IntVal 2)) (Const (IntVal 3))), "")],正确解析不等于运算。

内容的提问来源于stack exchange,提问作者Piskator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 13:35:15