Haskell有sum函数
sum :: Num a => [a] -> a
可以很好地组合成用
对矩阵求和sum . map sum :: Num a => [[a]] -> a
更深入一些,比如对一个立方体求和,就会创建限制Num [a]
sum . map sum . map sum :: (Num a, Num [a]) => [[[a]]] -> a
仔细想想,这是很自然的。因此,由于前一种定义sumcube函数的尝试让人不知所措,我们需要找到另一条路径。一个这样的尝试是:
sum . map sum . map (map sum) :: Num a => [[[a]]] -> a
似乎没有什么比求和函数更自然的了。
在我寻求在Haskell中拥有解决问题的心理工具的过程中,我有兴趣知道如何解决这个问题,即通过堆叠map sum
s来解决任何深度的结构求和的问题,就像我的第三个代码示例一样。这有可能吗?在这种情况下,你会怎么做?
类型类呢?
class Summable a where
total :: a -> Int
instance Summable Int where
total = id
instance Summable x => Summable [x] where
total = sum . map total
total ([[[1,2,3],[4,5]],[[6],[7,8,9,10]]] :: [[[Int]]])
--55
你必须从内到外工作。当你有一个用于对数据结构求和的函数f
时,那么sum . map f
就是对这些数据结构列表求和的方法。
sum :: Num a => [a] -> a
sum . map sum :: Num a => [[a]] -> a
sum . map (sum . map sum) :: Num a => [[[a]]] -> a
也许是这个?假设结合性,但添加新层很简单
sum . concat . concat :: Num c => [[[c]]] -> c
根据前一个维度的sum
来定义一个额外维度的sum
,这对我来说是最自然的。
-- given sum :: Num a => [a] -> a
sum2 :: [[a]] -> a
sum2 = sum . map sum
sum3 :: [[[a]]] -> a
sum3 = sum . map sum2
sum4 :: [[[[a]]]] -> a
sum4 = sum . map sum3
这与Sjoerd所说的基本相同。如果你想只使用map
和sum
和而不是,将常见的子表达式重构成有用的名称…然后使用等式推理来替换自定义函数sum2
, sum3
等
首先,有模板Haskell (GHC扩展虽然)。或者你可以使用data
,它支持任意深度列表嵌套,像这样:
data Tree a = Leaf a | Node [Tree a]
sumTree (Leaf x) = x
sumTree (Node xs) = (sum . map sumTree) xs
main = print $ sumTree $ Node [ Node [Leaf 3, Leaf 4, Leaf 5]
, Node [Leaf 1, Leaf 4, Leaf 2]]
将在这里打印19
。然而,这并不能确保所有的叶子都有相同的嵌套深度,我不知道如何从列表中构建这一点。