在定义了以下简单的树结构之后
data Tree a = Leaf | Branch (Tree a) a (Tree a)
Run Code Online (Sandbox Code Playgroud)
我尝试Foldable为它定义一个实例,只定义foldMap和使用foldrDefault和foldlDefault函数:
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
Run Code Online (Sandbox Code Playgroud)
然而,这会导致:
The value of treeFoldableInstance is undefined here, so this reference is not allowed.
Run Code Online (Sandbox Code Playgroud)
当我定义foldl并foldr明确地,它编译.这个错误的文档告诉我有关懒惰的信息,但这在哪里适用?
这是由于使用foldlDefault和foldrDefault要求您正在尝试构建的字典而发生的,并且由于严格评估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
Run Code Online (Sandbox Code Playgroud)
通过eta扩展foldr和foldl定义,它延迟了自引用,因为desugared代码变成类似于:
foldr = \f -> foldrDefault treeFoldableInstance f
Run Code Online (Sandbox Code Playgroud)
所以引用treeFoldableInstance只是在f传入之后才进行评估,而不是在声明之前进行评估treeFoldableInstance.