如何将我自己的数据构造函数转换为 Haskell 中的列表

How to convert my own Data constructor to List in Haskell

我在使用 Python 后才开始尝试 Haskell,我在理解它时遇到了很多问题

例如,在我尝试创建一个名为 ListBag 的新类型并编写一个简单的函数将列表转换为 ListBag 之后,我无法返回并对该数据执行任何操作:

data ListBag a = LB [(a,Int)] deriving (Show,Eq)

fromList :: (Ord a) => [a] ->ListBag a
fromList xs = LB [ y| y<- ys]
            where ys = toList(fromListWith (+) [(x, 1) | x <- xs])

a :: [Integer]
a=[1,1,1,1,1,1,2,2,2,3,3,3,3,4,5,5]
b = fromList a

现在 b 是:

LB [(1,6),(2,3),(3,4),(4,1),(5,2)]

并且因为 bb :: ListBag Integer 它不能被映射或者... 那么如何将它再次转换为列表呢?

首先,您的 ListBag 不会保存元素在初始列表中的顺序,但是...您可以像这样将 ListBag a 转换为 [a]

toList :: ListBag a -> [a]
toList (LB ys) = concat $ (\(y, n) -> replicate n y) <$> ys

并且您可以将 fromList 重新定义为

fromList xs = LB $ toList $ fromListWith (+) [ (x, 1) | x <- xs]

因为[ y | y <- ys]~ysx where x = y~y

啊,单子

toList :: ListBag a -> [a]
toList (LB l) = do
  (what, howmany) <- l
  replicate howmany what

或者如果你喜欢列表理解:

toList (LB l) =
  [x | (what, howmany) <- l, x <- replicate howmany what] 

诀窍是利用列表上的单子绑定可以将任意数量的东西放在每个元素的位置这一事实。所以对于每一对 (what, howmany) 我们输出 howmanywhats.

这与SergeyKuz1001的解决方案没有太大区别,只是风格不同。由于优化,我相信所有版本的性能都相当。

@SergeyKuz1001 的回答非常好。当你准备好更上一层楼时,你可以使用 List 的 Monad 实例和一些组合器来使 toList 非常简洁。

toList :: ListBag a -> [a]
toList (LB ys) = ys >>= uncurry (flip replicate)