Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite sequence with repeating elements

Tags:

f#

I need to create an infinite sequence containing a subsequence of elements which repeats infinitely.

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

So I wrote this:

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

Is there a standard way (function) to do this?

like image 958
Max Avatar asked Jan 18 '12 23:01

Max


3 Answers

Similar to Daniel's answer, but encapsulating it into a function, and pretending that function is in the Seq module:

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)
like image 71
Kit Avatar answered Nov 05 '22 16:11

Kit


I think that your approach is good in this scenario. There is no built-in function to implement repetition, but if you need to repeat sequences often, you can define one yourself and make it available in the Seq module:

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

Then you can nicely write Seq.repeat [ 1 .. 4 ], as if repeat was a standard F# library function, because F# IntelliSense shows both functions from your Seq module and from the Seq module as if they were defined in a single module.

Aside from your implementation, you can also use recursive sequence expression, which is another quite common pattern when generating sequences. Using while is in some ways imperative (although you don't need any state for simple repetitions) compared to functional recursion:

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

This approach is better when you want to keep some state while generating. For example, generating all numbers 1 .. using while would not be so nice, because you'd need mutable state. Using recursion, you can write the same thing as:

let rec numbersFrom n = 
  seq { yield n
        yield! numbersFrom (n + 1) }
like image 18
Tomas Petricek Avatar answered Nov 05 '22 18:11

Tomas Petricek


I don't think there's an idiom for this, and what you have is fine, but here are some alternatives.

If you change your subsequence to an array, you can do

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

Using what you have, you could also do

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

but it's no shorter.

like image 3
Daniel Avatar answered Nov 05 '22 16:11

Daniel