18

如果我有递归 ADT

data MyType = A | B | C MyType | D MyType MyType

我可以编写一个函数来确定一个实例是否MyType包含A这样的:

hasA :: MyType -> Bool
hasA A = True
hasA B = False
hasA (C x) = hasA x
hasA (D x y) = (hasA x) || (hasA y)

这适用于非循环实例,但它不会停止循环结构,例如

let x = C x in hasA x

相反,在这个例子中它应该返回False. 在其他情况下(使用D),它会错误地不停止而不是返回True

所以,问题是我如何最容易地编写像hasA在循环结构上工作的函数?Racket对此有一个特别好的功能define/fix,它允许您使函数像hasA预期的那样运行并返回False上面示例中的结构,几乎没有任何额外的代码。有没有办法在 Haskell 中做类似的事情?它有扩展名吗?

编辑:我现在发现它define/fix实际上是由 Matt Might 创建的宏,它利用了 Racket 的元编程功能,而不是内置功能,但这并没有使它成为 Racket 的一个重要功能。也许这个宏可以在 Haskell 中重现?

4

1 回答 1

11

在 Hackage 上搜索的关键词是可观察共享。这些结果中的data-reify包看起来特别相关:

data-reify提供 [原文如此] 将递归结构转换为显式图的能力。许多(隐式或显式)递归数据结构可以通过类型类实例获得这种能力。这为使用 Ref 进行可观察共享提供了一种替代方法。

于 2013-10-13T00:44:35.173 回答