【问题标题】:How can I dynamically allocate cyclic data?如何动态分配循环数据?
【发布时间】:2022-01-24 19:53:43
【问题描述】:

为了举例,让我们定义一个玩具自动机类型:

data Automaton =
  Auto
    { success ::
      Automaton
    , failure ::
      Automaton
    }

这个结构是按循环设计的,我们可以把每一个Automaton想象成一个状态,成功和失败转换到其他状态。所以有限自动机必须递归定义。例如这里是最简单的自动机:

sink =
  Auto sink sink

它由 1 个状态组成,该状态始终转换为自身。如果我们愿意,我们可以制作更复杂的自动机:

-- Transitions to a sink once it encounters a failure
otto1 =
  Auto otto1 sink

-- Mutually recursive automata
otto2 =
  Auto otto2 otto3

otto3 =
  Auto otto3 otto2

这些很好。但是接受用户输入并构建一个自动机可能会很好。例如,可以从转换矩阵中构建一个。这是一个简单的实现:

fromTransition :: [(Int, Int)] -> Automaton
fromTransition tMatrix =
  go 0
  where
    go n =
      let
        (succ, fail) =
          tMatrix !! n
      in
        Auto (go succ) (go fail)

但是,当我们尝试这样做时,就会出现问题。我们之前的例子是 O(1) 跟随转换。然而,由此产生的自动机是O(n) 跟随转换,因为除非缓存,每次我们进行转换时都必须索引一个列表。此外,只要这个自动机存在,输入列表就必须保存在内存中。这基本上比使用转移矩阵作为自动机更糟糕。

我真正想要的是使用该方法动态构建的自动机与之前所示的静态构建的自动机一样高效。我想要一些方法来分析输入,构造一个自动机,然后释放输入。

在具有变异的语言中,这很容易做到,因为我们可以一点一点地创建结构,留下漏洞以便以后更正。

我也非常希望不要将IO 拖进来,因为一旦引入它就无法包含。

有没有像我想要的那样动态分配循环结构的好方法?

【问题讨论】:

  • 迂腐提示:照原样,您的 Automaton 类型不是很有用,因为无法区分一个值与另一个值。所以,fromTransition _ = let a = Auto a a in a技术上是一个正确的答案。当然,在Automaton 中添加一些字段,比如Int,让问题不再微不足道。

标签: haskell memory-management recursive-datastructures


【解决方案1】:

懒惰的救援。我们可以递归地定义所有子自动机的列表,以便它们的转换索引到同一个列表中:

fromTransition :: [(Int, Int)] -> Automaton
fromTransition m = a !! 0 where
  a = map (\(succ,fail) -> Auto (a !! succ) (a !! fail)) m

在所有转换至少遍历一次之后,生成的自动机将是您期望的循环图,无需任何矩阵参考(特别是,转换将在恒定时间内进行)。

我们还可以使用seq 提前强制自动机。

fromTransition :: [(Int, Int)] -> Automaton
fromTransition m = forced `seq` (a !! 0) where
  a = map (\(succ,fail) -> Auto (a !! succ) (a !! fail)) m
  forced = foldr (\(Auto x y) r -> x `seq` y `seq` r) () a

【讨论】:

  • 您可以通过使用fromDistinctAscList (zip [0..] m) 将转换矩阵转换为IntMap (Int, Int) 来减少构建时间,然后只需fmapping 它以生成a。现在查找是对数时间并且速度很快。
  • 就此而言,您可以对数组执行相同的操作!除了列表之外的任何内容。
  • 我相信这有时被称为“打结”;如果您想了解有关此方法的更多信息,这是一个很好的搜索词。
  • fromTransition ((0,0):undefined) 不应该工作吗?还有... ((0,1),(1,0):undefined); a.o.t. ... ((0,1),(1,2):undefined).
  • 这将是一个 DFS,避免循环和重复工作的逻辑可能有点棘手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多