Подтвердить что ты не робот

Бесконечная последовательность с повторяющимися элементами

Мне нужно создать бесконечную последовательность, содержащую подпоследовательность элементов, которая бесконечно повторяется.

[1; 2; 3; 4; 1; 2; 3; 4; 1; 2; 3; 4; ...]

Итак, я написал это:

let l = [1; 2; 3; 4]
let s = seq { while true do yield! l }

Существует ли стандартный способ (функция)?

4b9b3361

Ответ 1

Я думаю, что ваш подход хорош в этом сценарии. Для реализации повторения нет встроенной функции, но если вам нужно часто повторять последовательности, вы можете определить ее самостоятельно и сделать ее доступной в модуле Seq:

module Seq = 
  let repeat items = 
    seq { while true do yield! items }

Затем вы можете красиво написать Seq.repeat [ 1 .. 4 ], как если бы repeat была стандартной библиотечной функцией F #, потому что F # IntelliSense показывает обе функции из вашего модуля Seq и модуля Seq, как если бы они были определены в единый модуль.

Помимо вашей реализации, вы также можете использовать выражение рекурсивной последовательности, которое является еще одним довольно распространенным шаблоном при генерации последовательностей. Использование while в некотором роде является императивным (хотя вам не нужно какое-либо состояние для простых повторений) по сравнению с функциональной рекурсией:

let rec repeat items = 
  seq { yield! items  
        yield! repeat items }

Этот подход лучше, если вы хотите сохранить некоторое состояние при генерации. Например, генерация всех чисел 1 .. с помощью while будет не такой приятной, потому что вам нужно изменить состояние. Используя рекурсию, вы можете написать то же самое, что:

let rec numbersFrom n = 
  seq { yield n
        yield! numbersFrom (n + 1) }

Ответ 2

Я не думаю, что для этого есть идиома, и то, что у вас есть, хорошо, но вот несколько альтернатив.

Если вы измените свою подпоследовательность на массив, вы можете сделать

let a = [|1; 2; 3; 4|]
let s = Seq.initInfinite (fun i -> a.[i % a.Length])

Используя то, что у вас есть, вы также можете сделать

let l = [1; 2; 3; 4]
let s = Seq.initInfinite (fun _ -> l) |> Seq.concat

но это не короче.

Ответ 3

Это сделает его как однострочный (более или менее), без необходимости создавать какие-либо вспомогательные объекты.

let s = seq { while true do
                for i in 1 .. 4 -> i }

Ответ 4

Как и Дэниел, ответьте, но инкапсулируя его в функцию и притворившись, что функция находится в модуле Seq:

module Seq =
    let infiniteOf repeatedList = 
        Seq.initInfinite (fun _ -> repeatedList) 
        |> Seq.concat

// Tests
let intList = [1; 2; 3; 4]
let charList = ['a'; 'b'; 'c'; 'd']
let objList = [(new System.Object()); (new System.Object()); (new System.Object()); (new System.Object())]
do
    Seq.infiniteOf intList |> Seq.take 20 |> Seq.iter (fun item -> printfn "%A" item)
    Seq.infiniteOf charList |> Seq.take 20 |> Seq.iter (fun item -> printfn "%A" item)
    Seq.infiniteOf objList |> Seq.take 20 |> Seq.iter (fun item -> printfn "%A" item)