对于树类型可折叠,“此处的实例值未定义,因此不允许此引用”

时间:2016-07-20 18:44:09

标签: purescript

定义以下简单树结构后

data Tree a = Leaf | Branch (Tree a) a (Tree a)

我尝试为其定义Foldable个实例,仅定义foldMap并使用foldrDefaultfoldlDefault函数:

instance treeFoldableInstance :: Foldable Tree where
  foldr = foldrDefault
  foldl = foldlDefault
  foldMap f Leaf = mempty
  foldMap f (Branch left a right) = foldMap f left <> (f a) <> foldMap f right

然而,这导致:

The value of treeFoldableInstance is undefined here, so this reference is not allowed.

当我明确定义foldlfoldr时,它会编译。这个错误的文档告诉我有关懒惰的信息,但这在哪里适用?

1 个答案:

答案 0 :(得分:7)

这是因为使用foldlDefaultfoldrDefault需要您正在尝试构建的字典,并且由于严格评估PureScript,这是不可能的。

这里最简单的解决方法可能就是尝试:

instance treeFoldableInstance :: Foldable Tree where
  foldr f = foldrDefault f
  foldl f = foldlDefault f
  foldMap f Leaf = mempty
  foldMap f (Branch left a right) = foldMap f left <> (f a) <> foldMap f right

通过eta扩展foldrfoldl定义,它会延迟自引用,因为desugared代码会变成类似:

foldr = \f -> foldrDefault treeFoldableInstance f

因此,treeFoldableInstance的引用仅在传入f后进行评估,而不是在treeFoldableInstance声明期间进行评估。