从初始状态开始返回DFA中的所有可达状态
我试图在Haskell中编写一个程序,该程序返回从初始状态开始的可达状态列表,类似于深度优先搜索。从初始状态开始返回DFA中的所有可达状态
states_reachable :: Eq st => DFA st -> [st]
states_reachable (qs, sigma, delta, s, inF) =
[delta q a | q <- qs, a <- sigma]
注:
- 适量是状态集合
- 西格玛的是字母表
- 增量是,需要一个状态和一个符号和一个过渡函数返回下一个状态
- 小号是初始状态
- INF是如果状态是接受状态,则返回true的函数,否则为假
作为功能现在被定义:
[delta q a | q <- qs, a <- sigma]
返回DFA中的所有状态(这是不正确的)。
我想通过从初始状态s开始填充列表并测试每个输入的delta函数。
例如:
// returns the states reachable from the initial state for all symbols in sigma
[delta s a | a <- sigma]
下一个步骤将是重复该过程为每个新状态加入到列表中。这可能会添加重复项,但我可以稍后删除它们。
然后我尝试:
[delta q a | q <- [delta s a | a <- sigma], a <- sigma]
我想这可能会奏效,但它并不因为它创建内部列表,然后用它来填充外部列表,然后停止。
我需要通过探索delta函数返回的所有新状态递归构建此列表。
您正试图计算关系的传递闭包,其中关系是“x可以一步到达y”。因此,我建议使用通用传递闭包解决方案,而不是DFA特定解决方案,然后从您的DFA中生成该关系。这里有一个相当基本的方式来做到这一点:
module Closure (closure) where
import Data.List (nub)
closure :: Eq a => (a -> [a]) -> a -> [a]
closure nexts init = go [init]
where go xs = let xs' = nub $ xs ++ (xs >>= nexts)
in if xs == xs'
then xs
else go xs'
这里的算法是有到达状态的列表,然后在每一步从每个到其所有的近邻散步展开它,然后nub
列表中摆脱重复。一旦该扩展步骤不添加新节点,就完成了。
现在,如何将DFA问题映射到此问题上?这并不难:您只需使用sigma
和delta
即可生成nexts
函数。在这里,我们需要假设您的DFA delta
函数是全部的,即每个节点都有一个针对sigma
中的每个字母指定的转换。这很容易创建一个额外的“故障”节点,所有节点可以过渡到,如果他们不喜欢他们的输入,所以我会假设已经完成。
neighbors :: (node -> letter -> node) -> [letter] -> node -> [node]
neighbors delta sigma n = map (delta n) sigma
有了到位,原来的问题简化为:
closure (neighbors delta sigma) s
我确定有一个更好的方法来用'iterate'或'unfoldr'或者更高的东西写'closure'级别比“如果”,但是当我尝试它变得非常混乱。 – amalloy 2014-10-26 21:19:13
让我想起本文http://matt.might.net/papers/might2011derivatives.pdf的,你也可以看看TDFA实现的灵感如何在Haskell中实现https://hackage.haskell.org/package/regex-tdfa – 2014-10-26 17:46:55