Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell foldMap采用了错误的参数类型?_Haskell_Monoids - Fatal编程技术网

Haskell foldMap采用了错误的参数类型?

Haskell foldMap采用了错误的参数类型?,haskell,monoids,Haskell,Monoids,以下是“向您学习”Haskell的一些示例: import qualified Data.Foldable as F data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)   instance F.Foldable Tree where       foldMap f Empty = mempty       foldMap f (Node x l r) = F.foldMap f l `mappen

以下是“向您学习”Haskell的一些示例:

import qualified Data.Foldable as F

data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)  

instance F.Foldable Tree where  
    foldMap f Empty = mempty  
    foldMap f (Node x l r) = F.foldMap f l `mappend`  
                             f x           `mappend`  
                             F.foldMap f r  

testTree = Node 5  
            (Node 3  
                (Node 1 Empty Empty)  
                (Node 6 Empty Empty)  
            )  
            (Node 9  
                (Node 8 Empty Empty)  
                (Node 10 Empty Empty)  
            )  
测试它:

> let z = F.foldMap (+) testTree
> :t F.foldMap
F.foldMap :: (Monoid m, F.Foldable t) => (a -> m) -> t a -> m
> :t (+)
(+) :: Num a => a -> a -> a
> :t z
z :: (Monoid a, Num a) => a -> a
F.foldable的第一个参数是一个返回幺半群的函数,但是Num不是幺半群的子类,所以这里肯定不限定(+)?但从测试来看,它似乎很合适

z
在这里有点神秘,它应该是一个幺半群,但具体是什么

“Num a=>”是一个typeclass约束,它指示(+)的参数和结果必须至少是typeclass“Num”的成员,但它们也可以是任何其他typeclass的完美成员(在本例中为Monoid)

关于z,有两个标准类型可以满足这些约束(同时是Num和Monoid的一部分)。它们是在Data.Monoid中定义的和和和积


为了回答您的问题,求和树或乘积树将通过类型检查并工作,您定义为typeclasses Num和Monoid一部分的任何其他类型也将通过类型检查并工作。

因此,让我们明确一下这里发生的情况。我们应该将这两种类型统一起来:

Num a => a -> a -> a
Monoid m => b -> m
这可以通过设置
b~a
m~a->a
来实现,从而

(Num a, Monoid (a -> a)) => a -> a -> a
此外,函数还有一个幺半群实例:

instance Monoid b => Monoid (a -> b) where
    mempty = \_ -> mempty
    mappend f g = \x -> f x `mappend` g x
(暂且不谈为什么这个实例有用。)这意味着,事实上,为了满足
Monoid(a->a)
约束,我们只需要确保返回类型--
a
--是一个Monoid,因此我们现在为
(+)
找到了这个类型:

对于
折叠贴图(+)
,此类型为:

其行为是遍历树,(部分)对树的每个元素应用
(+)
,然后使用
mappend
组合所有结果。因此,小示例树
节点3(节点1为空)(节点6为空)
将产生如下结果:

(mempty `mappend` (+) 1 `mappend` mempty) `mappend`
(+) 3                                     `mappend`
(mempty `mappend` (+) 6 `mappend` mempty)
为了简洁起见,让我们把它写成
mconcat[(1+),(3+),(6+)
,尽管这有点含糊其辞。在较大的示例树上运行
foldMap(+)
将是
mconcat[(1+),(3+),(6+),(5+),(8+),(9+),(10+)

现在,通过计算函数上的幺半群实例,我们发现
mconcat[f,g,h]=\x->mconcat[fx,gx,hx]
,等等,还有更多的函数。所以
foldMap(+)testTree
出来

\n -> mconcat [1+n, 3+n, 6+n, 5+n, 8+n, 9+n, 10+n]
可能您希望
foldMap(+)testTree
的结果是
1+3+6+5+8+9+10
;希望您能看到实际结果与您的预期有显著差异(以及原因)

如果我们想做的是把一棵树的所有元素相加,我们实际上可以意外地完成这项工作。我们可以特别选择
Sum
幺半群,并选择
n
0
:例如

getSum $ foldMap (+) testTree 0
= { by our computations above }
getSum $ (\n -> mconcat [1+n, 3+n, 6+n, 5+n, 8+n, 9+n, 10+n]) 0
= { beta reduction }
getSum $ mconcat [1+0, 3+0, 6+0, 5+0, 8+0, 9+0, 10+0]
= { n+0 = n }
getSum $ mconcat [1, 3, 6, 5, 8, 9, 10]
= { definition of mconcat for Sum }
getSum $ sum [1, 3, 6, 5, 8, 9, 10]
= { playing fast and loose with polymorphic literals }
sum [1, 3, 6, 5, 8, 9, 10]

这是一种非常复杂的方法来计算树中元素的总和。但希望这能解释为什么你写的不仅仅是一个类型错误;
z
的含义是什么;为什么
Num
既不是
Monoid

的子类也不是超类并不重要,您可能会发现
的这段输出:i Monoid
很有趣:
实例Monoid b=>Monoid(a->b)
,虽然它没有直接回答你的问题:你几乎肯定是指
F.foldMap Sum
而不是
F.foldMap(+)
。。。或者可能是
F.foldr(+)0
。请注意
F.foldMap(+)
可以进行类型检查,但它不会对树的元素求和。
\n -> mconcat [1+n, 3+n, 6+n, 5+n, 8+n, 9+n, 10+n]
getSum $ foldMap (+) testTree 0
= { by our computations above }
getSum $ (\n -> mconcat [1+n, 3+n, 6+n, 5+n, 8+n, 9+n, 10+n]) 0
= { beta reduction }
getSum $ mconcat [1+0, 3+0, 6+0, 5+0, 8+0, 9+0, 10+0]
= { n+0 = n }
getSum $ mconcat [1, 3, 6, 5, 8, 9, 10]
= { definition of mconcat for Sum }
getSum $ sum [1, 3, 6, 5, 8, 9, 10]
= { playing fast and loose with polymorphic literals }
sum [1, 3, 6, 5, 8, 9, 10]