如果我有递归 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 中重现?