如果我有递归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
实际上是a macro created by Matt Might,它充分利用了Racket的元编程功能,而不是内置功能,但这并不能减少它的影响。 Racket的一大特色。也许这个宏可以在Haskell中重现?
答案 0 :(得分:11)
在Hackage上搜索的关键词是observable sharing。这些结果中的data-reify包看起来特别相关:
data-reify
提供了[sic]将递归结构转换为显式图的能力。许多(隐式或显式)递归数据结构可以通过类型类实例赋予此功能。这为使用Ref进行可观察共享提供了另一种选择。