问题描述
我在使用 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)]
并且因为 b
是 b :: 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]
~ ys
和 x 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)
,我们输出 howmany
个 what
。
这与 SergeyKuz1001 的解决方案没有太大区别,只是风格不同。由于优化,我相信所有版本的性能都相当。
,@SergeyKuz1001 的回答非常好。当您准备好更上一层楼时,您可以使用 List
的 Monad 实例和一些组合器使 toList
非常简洁。
toList :: ListBag a -> [a]
toList (LB ys) = ys >>= uncurry (flip replicate)