[] parseParens "(())" --> [[]] parseParens "((()(-6ren">
gpt4 book ai didi

list - 将括号字符串解析为 Haskell 中的嵌套列表

转载 作者:行者123 更新时间:2023-12-04 23:14:05 29 4
gpt4 key购买 nike

我的目标是编写一个函数来将嵌套括号字符串解析为相应的列表:

parseParens "()" --> []
parseParens "(())" --> [[]]
parseParens "((()()))" --> [[[],[]]]

首先,我发现我无法轻松指定返回值的类型。我可以做这样的事情:
parseParens :: String -> [[[[t]]]]

但是我怎么说它是无限嵌套的呢?我猜 Haskell 不允许这样做。

我的解决方案

我想出了我自己的数据类型:
data InfiniteList = EmptyList | Cons InfiniteList InfiniteList deriving (Show)

还有一个使用这个的解析器函数:
parseParens :: String -> InfiniteList
parseParens ('(':xs) =
if remainder == ""
then result
else error "Unbalanced parenthesis"
where (result, remainder) = parseToClose EmptyList xs
parseParens _ = error "Unbalanced parenthesis"

parseToClose :: InfiniteList -> String -> (InfiniteList, String)
parseToClose acc "" = error "Unbalanced parenthesis!"
parseToClose acc (')':xs) = (acc, xs)
parseToClose acc ('(':xs) = parseToClose (concatInfLists acc (Cons result EmptyList)) remainder
where (result, remainder) = parseToClose EmptyList xs

concatInfLists :: InfiniteList -> InfiniteList -> InfiniteList
concatInfLists EmptyList ys = ys
concatInfLists (Cons x xs) ys = Cons x (concatInfLists xs ys)

像这样工作:
parseParens "()" --> EmptyList
parseParens "(())" --> Cons EmptyList EmptyList
parseParens "((()()))" --> Cons (Cons EmptyList (Cons EmptyList EmptyList)) EmptyList

怎么提高?

肯定有更好的方法来做到这一点。也许甚至有一种方法可以为此使用内置的 List 数据类型?

最佳答案

编辑:修正了我对本杰明回答的错误描述。

虽然@Benjamin Hodgson 评论中的答案是:

data Nested a = Flat a | Nested (Nested [a]) deriving (Show)

给出了一种表示任意嵌套深度的同构列表的好方法(即,有点像 [a][[a]][[[a]]] 加上所有其余的总和类型),这似乎是您问题的不寻常表示,特别是在这样的情况下:
parseParens "(()(()))"

其中“子节点”的嵌套深度不同。这将表示为:
Nested (Nested (Nested (Flat [[],[[]]]))) :: Nested a

所以它实际上允许你将解析的结果表示为所需的列表,如果有足够的 Nested构造函数,但它有一些奇怪的属性。例如,最里面的空列表实际上有不同的类型:第一个是类型 [[a]]而第二个类型是 [a] .

作为替代方法,我认为您的数据类型 实际上想要的可能只是:
data Nested = N [Nested] deriving (Show)

其中每个节点 N是一个(可能是空的)节点列表。然后,你会得到:
> parseParens "()"
N []
> parseParens "(())"
N [N []]
> parseParens "((()()))"
N [N [N [],N []]]
> parseParens "(()(()))"
N [N [],N [N []]]

如果你只是忽略 N这些结果中的构造函数,其中前三个与问题开头的“对应列表”测试用例相匹配。

作为旁注: Nested上面的数据类型实际上是一个不包含数据的“玫瑰树”,相当于 Tree ()使用 Tree来自 Data.Tree 的数据类型在 containers包裹。

最后,我再怎么强调学习和使用 monadic 解析库是多么有帮助,即使对于简单的解析工作也是如此。使用 parsec库,例如,您可以在一行中为您的语法编写一个解析器:
nested = N <$> between (char '(') (char ')') (many nested)

我的完整代码 parseParens是:
import Data.Tree
import Text.Parsec
import Text.Parsec.String

data Nested = N [Nested] deriving (Show)

nested :: Parser Nested
nested = N <$> between (char '(') (char ')') (many nested)

parseParens :: String -> Nested
parseParens str =
let Right result = parse (nested <* eof) "" str
in result

关于list - 将括号字符串解析为 Haskell 中的嵌套列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47577124/

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