1

我一直在尝试在 Haskell 中学习函数解析,作为练习,我想编写一个简单的元组解析器,使用函数betweensepBy1in Text.ParserCombinators.ReadP. 本质上我想要tupleAsIntPair :: ReadP (Int, Int),当使用它解析时ReadP_to_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)",我得到一个 no parse 错误。另一方面,如果我定义noparensglobal 并 run (readP_to_S noparens) "(3,4)",我会得到[("3,4","")],如果我 run (readP_to_S $ sepBy1 (many1 $ satisfy isNumericOrSep) sep) "3,4",我会得到一个 list [(["3"],",4"),(["3,"],"4"),(["3","4"],""),(["3,4"],"")],所以至少解析器sepBy1正在做一些事情,即使我只想要第三次解析。

我认为我正在编写两个解析器between并且sepBy1不正确,或者可能sepBy1没有做我认为应该做的事情。我如何实际实现这个元组解析器?我也将不胜感激任何风格的建议(例如,tuplify2让我有点烦恼)。

4

1 回答 1

3

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

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

所以,你不想定义isNumeric吗?为什么在这个定义中需要分隔符?

第二个问题是组合器的顺序。sep您的描述在两个 之间解析noparens,其中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

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

顺序也是从左到右。首先open,然后是解析器p,最后close被解析。

于 2013-09-03T06:58:10.763 回答