问题
This is a function that produces an infinite list of random numbers
import System.Random
values :: [Int]
values = map fst $ scanl (\(r, gen) _ -> randomR (1,10) gen) (randomR (1,10) (mkStdGen 1)) $ repeat ()
I want to reduce sequences for duplicate elements into one element e.g [2,3,4,1,7,7,7,3,4,1,1,1,3,..] -> [2,3,4,1,7,3,4,1,3,..]
So, I need some elegant function "f" from [Int] -> [Int] that do this. Also, it must work with an infinite list lazily, so if I run
f values
it must not hang and output data in real-time
回答1:
You can work with group :: Eq a => [a] -> [[a]] to make a list of groups. So for the given sample data, this will generate:
Prelude> import Data.List(group)
Prelude Data.List> group [2,3,4,1,7,7,7,3,4,1,1,1,3]
[[2],[3],[4],[1],[7,7,7],[3],[4],[1,1,1],[3]]
Then we can for each sublist only yield the first element with head, we know that such element exists, since otherwise it would never have constructed a new group in the first place:
Prelude Data.List> map head (group [2,3,4,1,7,7,7,3,4,1,1,1,3])
[2,3,4,1,7,3,4,1,3]
This thus means that you can define f as:
import Data.List(group)
f :: Eq a => [a] -> [a]
f = map head . group
This works on infinite lists as well. For example if we end the list with an infinite list of 5s, then it processes the list until that five and keeps looking for a new value:
Prelude Data.List> map head (group (2 : 3 : 4 : 1 : 7 : 7 : 7 : 3 : 4 : 1 : 1 : 1 : 3 : repeat 5))
[2,3,4,1,7,3,4,1,3,5
or we can make use of the group :: (Foldable f, Eq a) => f a -> [NonEmpty a] of Data.List.NonEmpty:
import Data.List.NonEmpty(group)
import qualified Data.List.NonEmpty as NE
f :: Eq a => [a] -> [a]
f = map NE.head . group
来源:https://stackoverflow.com/questions/65437663/haskell-elegant-way-to-filter-reduce-sequences-of-duplicates-from-infinte-list