2017-05-05 93 views
1

我实现可折叠,数据结构如下:暧昧发生 'foldMap'

data Tree a = Leaf a | Node (Tree a) (Tree a) deriving Show 

当我执行倍和foldMap:

instance Foldable Tree where 

--fold :: Monoid a => Tree a -> a 
fold (Leaf x) = x 
fold (Node l r) = fold l `mappend` fold r 

--foldMap :: Monoid b => (a -> b) -> Tree a -> b 
foldMap f (Leaf x) = f x 
foldMap f (Node l r) = foldMap f l `mappend` foldMap f r 

我会收到以下错误:

Ambiguous occurrence ‘foldMap’ 
    It could refer to either ‘Main.foldMap’, 
          defined at Chapterh14.hs:57:1 
          or ‘Prelude.foldMap’, 
          imported from ‘Prelude’ at Chapterh14.hs:1:1 
          (and originally defined in ‘Data.Foldable’) 

Chapterh14.hs:58:46: 
    Ambiguous occurrence ‘foldMap’ 
    It could refer to either ‘Main.foldMap’, 
          defined at Chapterh14.hs:57:1 
          or ‘Prelude.foldMap’, 
          imported from ‘Prelude’ at Chapterh14.hs:1:1 
          (and originally defined in ‘Data.Foldable’) 

Chapterh14.hs:71:13: 
    Ambiguous occurrence ‘foldMap’ 
    It could refer to either ‘Main.foldMap’, 
          defined at Chapterh14.hs:57:1 
          or ‘Prelude.foldMap’, 
          imported from ‘Prelude’ at Chapterh14.hs:1:1 
          (and originally defined in ‘Data.Foldable’) 

当我删除foldMap的定义时,我将得到以下警告:

No explicit implementation for 
     either ‘foldMap’ or ‘foldr’ 
    In the instance declaration for ‘Foldable Tree’ 
Ok, modules loaded: Main. 

当我实现函数时,我会得到它已经存在的错误,但是当我没有实现该函数时,我会得到一个警告,表明函数丢失了?我究竟做错了什么?

回答

4

您只需要将您的foldfoldMap声明缩进,以便它们成为instance的一部分。

instance Foldable Tree where 
    --fold :: Monoid a => Tree a -> a 
    fold (Leaf x) = x 
    fold (Node l r) = fold l `mappend` fold r 

    --foldMap :: Monoid b => (a -> b) -> Tree a -> b 
    foldMap f (Leaf x) = f x 
    foldMap f (Node l r) = foldMap f l `mappend` foldMap f r 

当你让他们取消缩进,该机看到一个空instance声明,呼吁foldfoldMap两个不相干的顶级功能。空实例是“没有显式实现”错误的来源(为什么这是一个警告,而不是我不知道的错误)。 “模糊发生”错误是因为编译器无法分辨对foldMap的递归调用是指代码中隐式导入的Prelude.foldMap还是Main.foldMap

+0

“为什么这是一个警告,而不是我不知道的错误” - 好点。也许这是因为每种方法都有一个默认定义?通常,通过这样的默认值是相互递归的,并且除非用户定义了某种方法,否则会简单地发生分歧。例如。 'Eq'有'==,/ ='默认,但是至少需要定义其中的一个才能正常工作。 – chi

+1

@chi它看起来总是一个警告,即使缺少的函数没有默认实现。 '实例Functor Foo where {}'只产生一个警告。我相信肯定有一个很好的理由... –

+0

@BenjaminHodgson我不确定你是否称它为“好”的理由,但偶尔你想使用一个思想不深的类(' Num',我在看着你......),尽管一些方法对你的类型没有完全意义。在这种情况下,默认的默认实现(不是错字 - 它是编译器为您编写的默认实现)调用'error'会很方便。 –