列出嵌套数据类型总和

时间:2018-04-16 00:07:40

标签: haskell

我有这种类型

data List a = EmptyL | ConsL a (List (a,a))

我写了这个函数

lenL :: List a -> Int
lenL EmptyL = 0
lenL (ConsL x xs) = 1 + lenL xs

我可以写一个这样的函数吗?

sumL :: List Int -> Int

如何?

3 个答案:

答案 0 :(得分:9)

不确定

data List a = EmptyL | ConsL a (List (a,a))

pair f (x, y) = (f x, f y)

nest :: (a -> b) -> List a -> List b
nest f EmptyL       = EmptyL
nest f (ConsL x xs) = ConsL (f x) (nest (pair f) xs)

sumL :: List Int -> Int
sumL EmptyL       = 0
sumL (ConsL x xs) = x + sumL (nest (uncurry (+)) xs)

我们有:

*Main> sumL EmptyL
0
*Main> sumL (ConsL 1 EmptyL)
1
*Main> sumL (ConsL 1 (ConsL (2, 3) EmptyL))
6

"魔法"解释如下:http://www.cs.ox.ac.uk/jeremy.gibbons/publications/efolds.pdf

为了完整起见,这里有一个关于广义fold的完整定义,如本文所述:

import Prelude hiding (sum, fold)

data List a = EmptyL | ConsL (a, List (a, a))

nest :: (a -> b) -> List a -> List b
nest f EmptyL          = EmptyL
nest f (ConsL (x, xs)) = ConsL (f x, nest (pair f) xs)

pair :: (a -> b) -> (a, a) -> (b, b)
pair f (x, y) = (f x, f y)

fold :: a -> ((b, a) -> a) -> ((b, b) -> b) -> List b -> a
fold e f g EmptyL          = e
fold e f g (ConsL (x, xs)) = f (x, fold e f g (nest g xs))

sum :: List Int -> Int
sum = fold 0 (uncurry (+)) (uncurry (+))

答案 1 :(得分:3)

您拥有的数据类型并非真正用于列表,更像是完整的二叉树。您可以将您拥有的树转换为普通列表,如下所示:

toList :: List a -> [a]
toList EmptyL = []
toList (ConsL x xs) = x:uncurry (++) (unzip (toList xs))

不是最有效的代码和排序有点武断,但它应该工作。如果你想要总和或其他任何东西,你可以使用sum . toList

请注意,您的lenL函数不会计算结果列表的长度,而是计算原始树的深度。如果您想要树中的元素数量,可以使用length . toList

答案 2 :(得分:1)

由于sumFoldable的一种方法,让我们看看我们如何实施foldMap

data List a = EmptyL | ConsL a (List (a,a))

instance Foldable List where
  foldMap _ EmptyL = mempty
  foldMap f (ConsL a as) = f a <> foldMap (\(x,y) -> f x <> f y) as

我们可以写sumL = getSum . foldMap Sum