Least expensive way to construct cyclic list in Haskell

落花浮王杯 提交于 2019-12-10 13:46:24

问题


So if I want to construct a circular list of n 0's and 1 1, which of the following ways is better/cheaper? And is there an even better/cheaper way? Taking into account that n is an Integer and may be large (though realistically its not going to exceed 2^32).

aZerosAndOnes :: Integer -> [Int]
aZerosAndOnes n 
    | n >= 0    = cycle (genericReplicate n 0 ++ [1])
    | otherwise = []

versus

bZerosAndOnes :: Integer -> [Int]
bZerosAndOnes n 
    | n >= 0    = tail (cycle (1 : genericReplicate n 0))
    | otherwise = []

回答1:


I'd definitely go with the second, because it's obviously efficient and plenty clear enough. The first will depend on whether genericReplicate is able to fuse with ++ in some fashion. The best way to find out for sure is to run

ghc -O2 -ddump-simpl -dsuppress-all whatever.hs | less

and pore over what it spews.


That said, the entire length of a cycle will actually be allocated in memory. Such is the nature of the cycle function as currently implemented, and that does not seem likely to change (barring some significant advance—foldr/build fusion does not seem to be sufficient). So you probably be better off avoiding this altogether by writing the rest of your code differently.


Ah yes, I thought of something else. If you consume this list in a "single-threaded" fashion, you can dispense with cycle altogether:

weirdthing n = genericReplicate n 0 ++ [1] ++ weirdthing n

and that's my final answer. This makes an infinite list instead of a cyclic list, but when n is big enough, that's better.



来源:https://stackoverflow.com/questions/25374736/least-expensive-way-to-construct-cyclic-list-in-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!