递归定义列表的内存泄漏问题

时间:2014-10-30 12:51:36

标签: haskell memory-leaks

问题背景

我目前正在尝试创建一个小Haskell EDSL来描述电子电路并模拟它们。我已经听说过熔岩,但我并没有真正读到它,因为我想要进行全面冒险"。我最终得到了一个类型类Bit,代表了你可以进行逻辑运算的任何东西,并使用列表来表示时间(第n个元素是第n个循环的值)。

问题本身

我的寄存器实现为reg input = ground : input,其中ground是表示逻辑false的Bit b => b。只要我不在自身上循环寄存器,这种实现就非常有效。事实上,当写alternate = not <$> (reg alternate)之类的东西时,我最终会构建not . not . not ... . not $ ground的巨大thunk而不是

iterate' f x = x `seq` x : (iterate' f (f x))
alternate = iterate' not ground

本来会更有效率。虽然,这不适用于不属于循环的寄存器,并且我不想将1)循环寄存器2)的语法分开而不是循环寄存器。

我有点卡在那里,但感觉这是一个非常普遍的问题,因此有人可能会有解决方案。

提前致谢!

1 个答案:

答案 0 :(得分:3)

如果您想尝试使用monadic方法,您可能需要查看LeventErkök的论文Value Recursion in Monadic Computations(第1.2章)和MonadFix package

巧合的是,Erkök通过展示Monadic电路描述和解释解决方案来激发他的研究。正如他所展示的,使用Monad,如果您需要不同的行为(例如简单地绘制而不是分析电路),则不必更改电路描述。这可能也非常有用,具体取决于您希望实施的程度。

从他的论文中了解解决方案:

halfAdd :: Circuit m => Sig Bool -> Sig Bool -> m (Sig Bool, Sig Bool)

halfAdd s1 s2 = do  
    sum <- xor s1 s2
    carry <- and s1 s2
    return (sum, carry)

看起来非常整洁(详见第1.2章),其中&gt;&gt; = 返回定义您的电路模型 m ,Sig是一个值列表,并使用 xor 等通用操作来转换类型类,....

更重要的是,他讨论了Monads中的递归(反馈循环)并指出你不想循环遍历电路元素,可能复制它们(并在你的情况下创建thunk)但是在实际的信号值上,因此需要值递归。

因此,具有反馈回路的非门看起来像:

toggle sig = mdo
    inp <- inv out
    out <- delay "False" False inp -- Used to define the initial signal value on the wire
    return out

请注意使用 mdo 而不是do,它允许(相互)递归定义。 (您必须启用RecursiveDo扩展才能获得对mdo的支持)。

在幕后,这将被翻译成

toggle sig = do
    mfix (\out -> do
        inp <- inv out
        out' <- delay "False" False inp
        return out')

(有关符号的更多信息,另请参阅https://www.haskell.org/haskellwiki/MonadFix。)

请注意,此解决方案以及mfix(针对您的特定电路模型/ monad)的定义不会生成任何中间门。 您可以在论文中找到所有设计和实施细节,以及有关有趣法律的更多材料。

也许这对你有所帮助。

编辑:提供更详细的答案。