如何将我自己的数据构造函数转换为 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,2,3,4,5,5]
b = fromList a

现在 b 是:

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

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

解决方法

首先,您的 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] 

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

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

,

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

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