2013-04-01 105 views
3

无论如何,我可以在Haskell中扩展列表的列表吗?在Haskell中扩展列表的列表

我试图写一个函数,生成[1,2,2,3,3,3,4,4,4,4 .....]这基本上是一个1,2个二, 3个三分球等

我尝试:

nnss :: [Integer] 
nnss = [nPrint x x | x <- [1,2..]] 

的问题,我的尝试是nPrint x x返回一个整数列表,例如,n打印2 2将返回[2,2]。无论如何,我可以将列表从[1,2,3 ...]扩展到[1,2,2,3,3,3 ...]?

+1

'nPrint'是这个坏名声(印刷是一个IO动作),是什么你使用的基本上只是“复制”。 – leftaroundabout

回答

8

我们正在寻找的函数签名是[[a]] -> [a],如果我们检查hoogle,我们发现concat是我们正在寻找的。

而在这种情况下,列表理解是不必要的,因为我们只是遍历每个项目,所以我们真的想做一个map。如此以来,结合mapconcat是如此普遍,我们可以只写

concatMap (\x -> nPrint x x) [1..] 

如果你是新来的Haskell但由于名单单子与concatMap定义我们也可以这样写

[1..] >>= \x -> nPrint x x 
+5

如果我们真的想玩哈斯克尔高尔夫球,我们可以做'[1 ..] >> = join replicate',使用'replicate'作为leftaroundabout上面提到的和'Control.Monad'的'join'函数(在这种情况下是for (( - >)r)'monad实例,类型为(r - > r - > a) - > r - > a')。 –

+0

啊谢谢,我试图想到一个功能 – jozefg

1
可以忽略此

你也可以把它写在不使用地图和列表级联(在固定时间内只是在前面加上):

nnss :: [Integer] 
nnss = genRepeated 1 1 

genRepeated :: Integer -> Integer -> [Integer] 
genRepeated x 0 = genRepeated (x+1) (x+1) 
genRepeated x y = x : genRepeated x (y-1) 

take 22 nnss == [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,6,6,6,6,6,6,7] 

其他快速的可能性是:

nnss :: [Integer] 
nnss = flatten [take x $ repeat x | x <- [1..]] 

flatten :: [[a]] -> [a] 
flatten [] = [] 
flatten ([]:xs) = flatten xs 
flatten ((x:xs):ys) = x : flatten (xs:ys) 
+1

这些都比我上面的时候比我慢 – jozefg

+0

@jozefg哦,它渐近或恒定时间更慢?你知道那是为什么吗?我并不是说它速度更快,更适合初学者,但我对造成差异的原因感兴趣。 – kyticka

+1

仅供参考您的自定义函数'flatten'只是'concat':http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:concat – stusmith

0

只需添加concat

nnss :: [Integer] 
nnss = concat [nPrint x x | x <- [1,2..]]