用树木简化Haskell中的正则表达式

Simplifying regex in Haskell with trees

我有这个正则表达式(re)的数据结构,到目前为止,我没有修改res的任何函数:

1
2
data Regex a = Letter a | Emptyword | Concat (Regex a) (Regex a) | Emptyset | Or (Regex a) (Regex a) | Star (Regex a)
    deriving (Show, Eq)

我想为我的资源实现一个简化算法。为此,我认为我应该首先将re表示为树,根据一些等价物更新树,然后将其转换回re。我的推理是,使用树,我将具有查找、提取和附加子树、更新值等功能。

然而,我很难找到一个树模块来提供这些功能,并且对于初学者来说足够简单。不过我发现这个AVL树包,似乎很大。

我想对我使用树的方法提出其他建议,并对支持上述功能的简单树模块提出建议。请注意,我是haskell的初学者,我还不了解monads,我对简化res的实现不感兴趣。

编辑1:我们知道以下两个结果是等效的,其中L b代表Letter bC代表Concat

1
2
3
4
5
    Or                          Or
   /  \                        / \
  L b  C            =        L b  L a
      /  \                        
    L a  Emptyword

因此,考虑到左边的re,我想用C标记的根替换子树,用L a标记的节点替换子树。如前所述,我的数据结构是一个树结构。但是,目前我没有函数来替换子树,例如,用节点替换子树,或者找到可以替换的结构子树。


正如注释中所指出的,您已经有了一棵树。您可以立即简化:

1
2
3
4
5
6
7
8
9
10
11
12
13
simplify :: Regex a -> Regex a
simplify (Star Emptyset)   = Emptyword
simplify (Star (Star x))   = Star (simplify x)
simplify (Concat x Emptyword) = simplify x
simplify (Concat Emptyword y) = simplify y
simplify (Or x y) | x == y = x
-- or rather simplify (Or x y) | simplify x == simplify y = simplify x
-- more sophisticated rules here
-- ...
-- otherwise just push down
simplify (Or x y) = simplify (Or (simplify x) (simplify y)
-- ...
simplify x@(Letter _) = x

这只是表面现象,例如第一条规则应该是simplify (Star x) | simplify x == Emptyset = emptyword

二叉平衡树

AVL树是为了平衡,这里不太适用。平衡唯一有意义的地方是关联运算。

1
Or (x (Or y z) == Or (Or x y) y

我建议在这些操作中使用列表

1
2
data Regex' a = Letter' a | Concat' [Regex a]  | Or [Regex a] | Star (Regex a)
deriving (Show, Eq)

(没有Emptyword',因为它是Concat' [];与Emptyset'Or相同。)对读者来说,在RegexRegex'之间转换是通常的做法。

一般硬度

请注意,regex等效并不容易:

1
(a|b)* = (a*b)*a*

优化Or"(a|b)*""(a*b)*a*"是困难的…