gpt4 book ai didi

haskell - Parsec 排列解析

转载 作者:行者123 更新时间:2023-12-04 12:49:24 30 4
gpt4 key购买 nike

我写了这样的排列解析例子:

data Entry = Entry {
first_name :: String
, last_name :: String
, date_of_birth :: Maybe String
, nationality :: Maybe String
, parentage :: Maybe String
} deriving (Show)

nameParser :: Parser (String, String)
nameParser = do
first_name <- many1 upper
endOfLine
last_name <- many1 letter
endOfLine
return $ (first_name, last_name)

attributeParser :: String -> Parser String
attributeParser field = do
string $ field ++ ": "
value <- many1 (noneOf "\n")
endOfLine
return value

entryParser :: Parser Entry
entryParser = do
(f, l) <- nameParser
(d, n, p) <- permute ((,,)
<$?> (Nothing, liftM Just (try $ attributeParser "Date of Birth"))
<|?> (Nothing, liftM Just (try $ attributeParser "Nationality"))
<|?> (Nothing, liftM Just (try $ attributeParser "Parentage"))
)
return $ Entry f l d n p

main = do
mapM_ putStrLn . map (show . parse entryParser "") $ goodTests

goodTests =
"AAKVAAG\nTorvild\nDate of Birth: 1 July\nNationality: Norwegian\nParentage: business executive\n" :
"AAKVAAG\nTorvild\nNationality: Norwegian\nParentage: business executive\n" :
"AAKVAAG\nTorvild\nParentage: business executive\nNationality: Norwegian\n" :
"AAKVAAG\nTorvild\nParentage: business executive\n" :
"AAKVAAG\nTorvild\nNationality: Norwegian\n" : []

最好扩展Entry将来有新字段的数据,但这样做需要在 entryParser 中放入更多重复代码功能。有没有办法让这个函数接受解析器列表?

我从这个开始:

attributeParsers =
map attributeParser ["Date of Birth", "Nationality", "Parentage"]

permuteParams =
map (\p -> (Nothing, liftM Just (try p))) attributeParsers

但无法以正确的方式折叠 permuteParams连同 <|?>运算符(我想这需要比 (,,) 元组构造函数更聪明的东西)。

最佳答案

作为第一步,您可以抽象出您为每个组件所做的事情:

attr txt = (Nothing, liftM Just (try $ attributeParser txt))

有了这个,你可以去:

entryParser :: Parser Entry
entryParser = do
(f, l) <- nameParser
(d, n, p) <- permute ((,,)
<$?> attr "Date of Birth"
<|?> attr "Nationality"
<|?> attr "Parentage"
)
return $ Entry f l d n p

然后,如果需要,您可以组合中缀组合器和 attr 调用:

f .$ x = f <$?> attr x
f .| x = f <|?> attr x

infixl 2 .$
infixl 2 .|

这给你:

entryParser :: Parser Entry
entryParser = do
(f, l) <- nameParser
(d, n, p) <- permute ((,,)
.$ "Date of Birth"
.| "Nationality"
.| "Parentage"
)
return $ Entry f l d n p

然后你可以通过去掉中间的三元组来进一步简化。您所做的只是构建它,然后将其组件应用于 Entry f l,因此您也可以将置换解析器的结果直接应用于 Entry f l:

entryParser :: Parser Entry
entryParser = do
(f, l) <- nameParser
permute (Entry f l
.$ "Date of Birth"
.| "Nationality"
.| "Parentage"
)

我认为这已经足够紧凑了。如果你真的想要某种折叠,你要么必须引入一个中间列表并将排列结果收集到一个列表中。然而,这仅在所有可置换属性都属于同一类型(它们目前是)的情况下才有效,并且不太好,因为您将对该列表中的元素数量做出假设。或者您将不得不使用异构列表/某种类型类魔法,这将导致类型更加复杂,我认为在这里不值得。

关于haskell - Parsec 排列解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41068075/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com