Parsing Haskell中的元组解析器

Parsing Haskell中的元组解析器,parsing,haskell,tuples,Parsing,Haskell,Tuples,我一直在尝试学习Haskell中的函数解析,作为练习,我想编写一个简单的元组解析器,使用Text.parsercompbinators.ReadP中介于和sepBy1之间的函数。本质上,我需要tupleAsIntPair::ReadP(Int,Int),当使用ReadP\u to\u S进行解析时,它接受一个字符串,例如“(3,4)”,并返回一对整数(3,4),该整数被装箱在ReadS中。目前我有: import Text.ParserCombinators.ReadP isNumericOr

我一直在尝试学习Haskell中的函数解析,作为练习,我想编写一个简单的元组解析器,使用
Text.parsercompbinators.ReadP
介于
sepBy1
之间的函数。本质上,我需要
tupleAsIntPair::ReadP(Int,Int)
,当使用
ReadP\u to\u S
进行解析时,它接受一个字符串,例如
“(3,4)”
,并返回一对整数
(3,4)
,该整数被装箱在
ReadS
中。目前我有:

import Text.ParserCombinators.ReadP

isNumericOrSep :: Char -> Bool
isNumericOrSep = flip elem $ "0123456789-, "

tuplify2 :: [Int] -> (Int, Int)
tuplify2 [x,y] = (x,y)

tupleAsIntPair :: ReadP (Int, Int)
tupleAsIntPair = fmap tuplify2 parsedList 
    where   parsedList = fmap (map read) $ sepBy1 noparens sep
            noparens = between open close $ many1 (satisfy isNumericOrSep)
            open = char '('
            close = char ')'
            sep = char ','
但是,当我尝试运行
(readP_to_S tupleAsIntPair)“(3,4)”
时,我得到一个无解析错误。另一方面,如果我全局定义
noparens
并运行
(readP_to_S noparens)”(3,4)”
,我会得到
[((“3,4”),如果我运行
(readP_to_$sepBy1(many1$said isNumericOrSep)sep)“3,4”
,我会得到一个
[([(“3“,”,“,”,“,”,“,“,”,“,“,”,“,“,”,“,”,“,”,“,”,“,”,“,”,“,”,“,”,“,”,”,“,”,“,”,“,”,”,“,”,“,“,”,”,“,“,”,”,“,所以至少解析器
sepBy1
正在做一些事情,尽管我只需要第三次解析


我认为我在
sepBy1
之间编写了两个解析器
,这是错误的,或者可能是
sepBy1
没有做我认为应该做的事情。我实际上如何实现这个元组解析器?我也希望得到任何风格上的建议(例如,
tuplify2
让我有点烦)。

第一个问题是你对
isNumericOrSep
的定义。您正在定义的列表包含作为元素的
。这意味着
isNumericOrSep
将解析用作分隔符的
,因此
parsedList
将由于缺少
sep
而失败

isNumericOrSep :: Char -> Bool
isNumericOrSep = flip elem $ "0123456789- "
那么,您不想定义
isNumeric
?为什么在此定义中需要分隔符

第二个问题是组合子的顺序。您的描述在两个
noparens
之间解析
sep
,其中
noparens
定义为一个左括号、多个(但至少一个)数值和一个右括号的组合。所以,我想你真正想要的是在开始括号和结束括号之间解析一个元组

tupleAsIntPair :: ReadP (Int,Int)
tupleAsIntPair = fmap tuplify2 parsedList
 where
  parsedList = fmap (map read) $ between open close $ sepBy1 noparens sep
  noparens = many1 (satisfy isNumericOrSep)
  open = char '('
  close = char ')'
  sep = char ','
这将产生以下结果:

 *Main> (readP_to_S tupleAsIntPair) "(3,4)"
 [((3,4),"")]
我可能误解了你的目标。但是在你的介绍中,我读到你想要解析一个元组,但也许你想要解析许多元组

编辑:

不首先解析括号。请看一下以下各项的定义:

between::ReadP open->ReadP close->ReadP a->ReadP a
--^@在打开-关闭p@之间解析@open@,后面跟着@p@最后
--   @close@. 只返回@p@的值。

开闭之间p=do u非常感谢您的帮助;这正是我想要的。检查一下,代码首先删除括号,然后解析逗号列表,对吗?那么我应该考虑从左到右组合解析器吗?对第二个问题是的,当你组合解析器时,从左到右组合更自然。对于第二个答案,我将编辑我的答案。
between :: ReadP open -> ReadP close -> ReadP a -> ReadP a
-- ^ @between open close p@ parses @open@, followed by @p@ and finally
--   @close@. Only the value of @p@ is returned.
between open close p = do _ <- open
                          x <- p
                          _ <- close
                         return x