鉴于此定义和测试矩阵:
data (Eq a, Show a) => QT a = C a | Q (QT a) (QT a) (QT a) (QT a)
deriving (Eq, Show)
data (Eq a, Num a, Show a) => Mat a = Mat {nexp :: Int, mat :: QT a}
deriving (Eq, Show)
-- test matrix, exponent is 2, that is matrix is 4 x 4
test = Mat 2 (Q (C 5) (C 6) (Q (C 1) (C 0) (C 2) (C 1)) (C 3))
| | |
| 5 | 6 |
| | |
-------------
|1 | 0| |
|--|--| 3 |
|2 | 1| |
我正在尝试编写一个输出列总和列表的函数,例如:[13, 11, 18, 18]
。基本思想是对每个子四叉树求和:
(C c)
,则输出重复2 ^ (n - 1)
次值c * 2 ^ (n - 1)
。 示例:第一个四叉树是(C 5)
所以我们重复5 * 2^(2 - 1) = 10
,2 ^ (n - 1) = 2
次,获得[5,5]。(Q a b c d)
,我们zipWith
a和c(和b和d)的colsum。当然这是无法正常工作(甚至没有编译),因为经过一些递归我们有:
zipWith (+) [[10, 10], [12, 12]] [zipWith (+) [[1], [0]] [[2], [1]], [6, 6]]
因为我从Haskell开始,我觉得我错过了什么,需要一些关于我可以使用的功能的建议。 不工作 colsum定义是:
colsum :: (Eq a, Show a, Num a) => Mat a -> [a]
colsum m = csum (mat m)
where
n = nexp m
csum (C c) = take (2 ^ n) $ repeat (c * 2 ^ n)
csum (Q a b c d) = zipWith (+) [colsum $ submat a, colsum $ submat b]
[colsum $ submat c, colsum $ submat d]
submat q = Mat (n - 1) q
任何想法都会很棒并且非常感激......
答案 0 :(得分:2)
可能“某人”应该解释谁担心QuadTree的深度,Matrix类型中的nexp字段确实用于确定(C _)的实际大小。
关于第一个答案中提出的解决方案,确定它有效。然而,构造和解构Mat是没有用的,这很容易避免。此外,调用fromIntegral来“绕过”来自使用复制的类型检查问题可以解决,而不必强迫首先进入Integral然后再回来,比如
设m = 2 ^ n; k = 2 ^ n,重复k(m * x)
无论如何,这里的挑战是避免因++而产生的二次行为,这就是我所期望的。
干杯,
答案 1 :(得分:1)
让我们考虑一下你的colsum
:
colsum :: (Eq a, Show a, Num a) => Mat a -> [a]
colsum m = csum (mat m)
where
n = nexp m
csum (C c) = take (2 ^ n) $ repeat (c * 2 ^ n)
csum (Q a b c d) = zipWith (+) [colsum $ submat a, colsum $ submat b]
[colsum $ submat c, colsum $ submat d]
submat q = Mat (n - 1) q
除了您定义csum (Q a b c d) = ...
的行外,它几乎是正确的。
让我们考虑类型。 colsum
返回一个数字列表。 ZipWith (+)
以元素方式对两个列表求和:
ghci> :t zipWith (+)
zipWith (+) :: Num a => [a] -> [a] -> [a]
这意味着您需要将两个数字列表传递给zipWith (+)
。而是创建两个数字列表列表,如下所示:
[colsum $ submat a, colsum $ submat b]
此表达式的类型为[[a]]
,而不是[a]
。
您需要做的是连接两个数字列表以获得一个数字列表(这可能是您打算做的):
((colsum $ submat a) ++ (colsum $ submat b))
同样,您连接c
和d
的部分和的列表,然后您的函数应该开始工作。
答案 2 :(得分:0)
让我们更加普遍,然后回到手头的目标。
考虑我们如何将四叉树投影到2 n ×2 n 矩阵中。我们可能不需要创建此投影来计算其列总和,但这是一个有用的概念。
现在考虑这种投影的列总和。
如果我们的四叉树是单个细胞,那么2 n 列的总和将全部为2 n 乘以存储在该单元格中的值。
(提示:查看hoogle上的replicate
和genericReplicate
。
否则,如果n≥1,则每列重叠两个不同的象限。 我们的一半栏目将完全由西方象限决定, 另一半是东部象限,是特定列的总和 可以定义为该列的贡献总和 从它的北半部(即北部象限中该列的列总和), 和它的南半部(同样)。
(提示:我们需要将西部列的总和附加到东部列的总和 得到所有列的总和,并结合北部和南部的半柱总和 得到每列的实际总和。)
同样,我们有第三种情况,这里的列总和取决于方式 你将四个子季度投影到1×1矩阵上。幸运的是,1×1矩阵意味着 只有一列总和!
现在,我们只关心一个特定的投影 - 投影到尺寸为2 d d×2 d 的矩阵上 其中d是我们的四叉树的深度。所以你也需要计算深度。既然一个 单个细胞“自然地”适合大小为1×1的矩阵,这意味着它具有一个 一个四分支必须具有足够大的深度,以允许其每个子标准适合 进入矩阵的象限。