элегантный способ haskell отфильтровать (уменьшить) последовательности дубликатов из бесконечного списка чисел

#haskell #filter #sequence

#haskell #Фильтр #последовательность

Вопрос:

Это функция, которая создает бесконечный список случайных чисел

 import System.Random
values :: [Int]
values = map fst $ scanl ((r, gen) _ -> randomR (1,10) gen) (randomR (1,10) (mkStdGen 1)) $ repeat ()
 

Я хочу уменьшить последовательности для повторяющихся элементов в один элемент, например
[2,3,4,1,7,7,7,3,4,1,1,1,3,..] -> [2,3,4,1,7,3,4,1,3,..]

Итак, мне нужна какая-нибудь элегантная функция «f» из [Int] -> [Int], которая это делает. Кроме того, он должен работать с бесконечным списком лениво, поэтому, если я запускаю

 f values
 

он не должен зависать и выводить данные в режиме реального времени

Комментарии:

1. f = map head . group

2. Ваше выражение для values может быть упрощено до randomRs (1,10) (mkStdGen 1)

Ответ №1:

Вы можете работать с group :: Eq a => [a] -> [[a]] , чтобы составить список групп. Таким образом, для данного образца данных это приведет к:

 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]]
 

Тогда мы можем для каждого подсписка получить только первый элемент с head , мы знаем, что такой элемент существует, поскольку в противном случае он никогда бы не создал новую группу в первую очередь:

 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]
 

Таким образом, это означает, что вы можете определить f как:

 import Data.List(group)

f :: Eq a => [a] -> [a]
f = map head . group 

Это также работает с бесконечными списками. Например, если мы заканчиваем список бесконечным списком 5 s, то он обрабатывает список до этих пяти и продолжает искать новое значение:

 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
 

или мы можем воспользоваться group :: (Foldable f, Eq a) => f a -> [NonEmpty a] 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 

Комментарии:

1. в целом безопасный способ сделать то же map head самое , что и есть concatMap (take 1) .

2. @WillNess: но здесь мы знаем, что подсписки не будут пустыми, есть вариант group , который генерирует NonEmpty s…

3. ну, технически, я не сказал «технически». 🙂