我试图在Haskell中编写一个程序,它返回从初始状态开始的可达状态列表,类似于深度优先搜索。
states_reachable :: Eq st => DFA st -> [st]
states_reachable (qs, sigma, delta, s, inF) =
[delta q a | q <- qs, a <- sigma]
注意:
现在定义了函数:
[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函数返回的所有新状态来递归地构建此列表。
答案 0 :(得分:3)
你在这里尝试计算关系的传递闭包,其中关系是&#34; x可以在一步中得到y&#34;。因此,我建议使用通用的传递闭包解决方案,而不是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问题映射到此?这并不太难:您只需要使用nexts
和sigma
生成delta
函数。在这里,我们需要假设您的DFA delta
函数是完全的,即每个节点都为sigma
中的每个字母指定了转换。通过创建一个额外的&#34;失败&#34;这很容易。所有节点都可以转换到的节点,如果他们不喜欢他们的输入,那么我只是假设已经完成了。
neighbors :: (node -> letter -> node) -> [letter] -> node -> [node]
neighbors delta sigma n = map (delta n) sigma
有了这个,原来的问题会缩小为:
closure (neighbors delta sigma) s