Parsing 如何从单词列表中生成Haskell解析器?

Parsing 如何从单词列表中生成Haskell解析器?,parsing,haskell,attoparsec,Parsing,Haskell,Attoparsec,我是Haskell初学者,使用ATOPASSERC在文本中查找一些颜色表达式。我希望能够匹配,例如,文本中的“浅蓝绿色”和“浅蓝绿色”。当然,我需要一个这样的字符串的广义解。所以我一直在想 "light" >> sep >> "blue" >> sep >> "green" where sep = inClass "\n\r- " stack runhaskell ThisFile.hs --package attoparsec replac

我是Haskell初学者,使用ATOPASSERC在文本中查找一些颜色表达式。我希望能够匹配,例如,文本中的“浅蓝绿色”和“浅蓝绿色”。当然,我需要一个这样的字符串的广义解。所以我一直在想

"light" >> sep >> "blue" >> sep >> "green"
  where sep = inClass "\n\r- "
stack runhaskell ThisFile.hs --package attoparsec replace-attoparsec text
换句话说,我想我需要一种方法将
>sep>>
插入到单词列表中。比如:

import qualified Data.Text as T
import Data.Attoparsec.Text

-- | Makes a parser from a list of words, accepting
-- spaces, newlines, and hyphens as separators.
wordListParser :: [T.Text] -> Parser
wordListParser wordList = -- Some magic here
或者也许我想的完全是错误的,还有更简单的方法吗

编辑:这个最小的不起作用的示例感觉就快到了:

{-# LANGUAGE OverloadedStrings #-}

import Replace.Attoparsec.Text
import Data.Attoparsec.Text as AT
import qualified Data.Text as T
import Control.Applicative (empty)

wordListParser :: [T.Text] -> Parser T.Text
wordListParser (w:ws) = string w >> satisfy (inClass " -") >> wordListParser ws
wordListParser [w] = string w
wordListParser [] = empty  -- or whatever the empty parser is

main :: IO ()
main = parseTest (wordListParser (T.words "light green blue")) "light green-blue"
我想可以用这样的东西运行

"light" >> sep >> "blue" >> sep >> "green"
  where sep = inClass "\n\r- "
stack runhaskell ThisFile.hs --package attoparsec replace-attoparsec text

我不熟悉attoparsec,但您可以使用递归解决方案:

wordListParser::[T.Text]->Parser
wordListParser[]=空
wordListParser[w]=文本w
wordListParser(w:ws)=文本w>>包含类“\n\r-”>>wordListParser ws

假设您有颜色的数据类型,我会这样做;如果你没有,就用它代替你正在使用的东西。函数
parsecolorgen
接受任何空格分隔的
Text
,并生成接受颜色的解析器,其中每个单词由一个或多个合法分隔符分隔

import Prelude hiding (concat, words)
import Control.Applicative ((<|>))
import Data.Attoparsec.Text
import Data.List (intersperse)
import Data.Text (concat, pack, singleton, Text,  words)

data Colour = LightBlue | DarkBlue | VibrantRed deriving Show

parseColourGen :: Text -> Parser [Text]
parseColourGen = sequence . intersperse (mempty <$ many1 legalSep) . 
                   fmap string . words

parseColour :: [(Text, Colour)] -> Parser Colour
parseColour = foldl1 (<|>) . fmap (\(text, colour) ->
  colour <$ parseColourGen text)

legalSep :: Parser Text
legalSep = singleton <$> satisfy (inClass "\n\r- ")
通过这种方式,您可以在一个位置配置所有颜色及其对应的颜色名称,然后可以像这样运行解析器:

> parse (parseColour wordList) $ pack "vibrant-red"
Done "" VibrantRed
编辑

在对你的问题进行编辑之后,我想我更了解你想要什么。FWIW,我仍然更喜欢上面的解决方案,但下面是如何修复最后一段代码:

  • 正如编译器应该告诉您的那样,模式
    (w:ws)
    [w]
    是重叠的,因此如果您希望运行时捕获单元素模式,必须将其放在顶部
  • a>>b
    表示“运行操作
    a
    ,放弃其结果,然后运行操作
    b
    并使用该结果”。这就是为什么解析器(使用上面的修复程序)将输出
    Done”““blue”
    。解决这个问题的一个简单方法是使用
    do
    表示法绑定所有三个计算的结果,并返回它们的串联
  • 下面是您的代码现在的样子:

    wordListParser :: [Text] -> Parser Text
    wordListParser [w] = string w
    wordListParser (w:ws) = do
      a <- string w
      b <- satisfy (inClass " -")
      c <- wordListParser ws
      return (a `append` (singleton b) `append` c) -- singleton :: Char -> Text
    wordListParser [] = empty
    
    wordListParser::[Text]->解析器文本
    wordListParser[w]=字符串w
    wordListParser(w:ws)=do
    
    a知道在哪里可以找到空解析器吗?我尝试了
    Parser T.empty
    T.empty
    ,但没有接近太多。@Jonathan第一个结果是正确的。这只是产生了一个部分解析,并没有完成。@Jonathan“它产生了一个部分解析”是什么意思?你能给出一个它不起作用的例子吗?我刚刚在我的问题中添加了一个例子,显示了它返回
    Partial\u
    的位置。你希望解析
    的结果是浅蓝绿色
    吗?你可能想使用
    sepBy1
    choice
    。结果应该是t.Text。我将如何使用
    seppy1
    ?我已经用您问题中的编辑更新了我的答案。