haskell 将带括号的数字字符串转换为树

ny6fqffe  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(136)

我正在开发一个函数来将带括号的数字串转换为树。例如,

treeFromString "((1)((3)(4)))" == Right (Nd (Lf 1) (Nd (Lf 3) (Lf 4)))

字符串
这是我的尝试。我假设一个格式良好的字符串来解决一个更简单的问题,但类型签名应该是Either String (BinL' Int)

import Data.Char

data BinL' a = Lf a | Nd (BinL' a) (BinL' a) deriving Show

treeFromString :: String -> BinL' Int
treeFromString [] = undefined
treeFromString ('(':cs) = case span isDigit cs of
                            ("", remaining) -> treeFromString cs
                            (digits, remaining) -> Nd (Lf (read digits)) (treeFromString remaining)


当传入的参数是一个空列表时,我应该返回什么值?
我的一般方法是实现我想要的东西的明智方法吗?
编辑:
有一个互补函数可以将树转换为带括号的字符串。我正在开发的函数应该执行相反的转换。示例:
showBinL' :: Show a => BinL' a -> String

showBinL' (Nd (Lf 1) (Nd (Lf 3) (Lf 4)))
"((1)((3)(4)))"

2q5ifsrm

2q5ifsrm1#

如果你不太关心效率,我推荐标准的初学者友好的方法:
事物的解析器
是一个字符串函数
到配对列表
事物和弦。
--格雷厄姆赫顿
而且,您很幸运:语言标准Read类将其解析器放在这个框架中。

reads :: Read a => String -> [(a, String)]

字符串
因此,如果您正在构建一种能够顺利处理这种类型的机制,那么当您需要读取一个数字时,您可以清楚地插入reads,实际上甚至可以从数字的阅读树推广到任何Read示例的阅读树。
所以这里是我建议你首先尝试实现的类型。如果你必须有一个特定的类型,你可以在之后写一个小的 Package 器来转换它。

treeFromString :: Read a => String -> [(BinL' a, String)]


在常见的情况下,如果字符串解析成功,结果列表将有一个元素,包含树和尚未解析的字符串的后缀(如果有的话);如果解析失败,结果列表应该是空的。
在你坐下来开始编写解析代码之前,最好先试着写下语法。下面是我对一个合理语法的猜测:树是一对括号,包含序列中的两个孩子或叶子的值。像这样:

T ::= '(' T T ')'
    | '(' <leaf> ')'


一个实现计划是构建一个小型的解析器库,可以组合这些解析器来生成这种语法。我推荐以下集合:

  • 一个解析器,只使用一个字符,不返回任何有趣的数据。
char :: Char
     -> (String -> [((), String)])

  • 一种排序两个解析器的方法,即首先解析一个东西,然后使用第一个解析器中剩余的文本来解析第二个东西。
andThen :: (String -> [(a, String)])
        -> (String -> [(b, String)])
        -> (String -> [((a, b), String)])

  • 一种交替使用两个解析器的方法,即在同一输入上尝试两个解析器,返回任何一个给出的结果。
orElse :: (String -> [(a, String)])
       -> (String -> [(b, String)])
       -> (String -> [(Either a b, String)])

  • 一种在解析器成功时转换解析器返回的数据的方法。
finally :: (String -> [(a, String)])
        -> (a -> b)
        -> (String -> [(b, String)])


有了这些,你可以直接将上面的语法翻译成解析器:

t :: Read a => String -> [(BinL' a, String)]
-- T ::=       '('           T           T                ')'
t      = (char '(' `andThen` t `andThen` t `andThen` char ')' `finally` \(_, (l, (r, _))) -> Nd l r)

--     |              '('           <leaf>               ')'
       `orElse` (char '(' `andThen` reads `andThen` char ')' `finally` \(_, (v, _)) -> Lf v)

相关问题