Recursive implementation of a zip function in F# I'm learning F# from Tomas Petricek's "Real-World Functional Programming" book. As suggested at one point in the book, I started implementing a zip function using a recursive sequence expression. I'm not very happy with my implementation and I would like to know how F# devs would refactor my implementation. I know that the original zip function is implemented using map2 but I want to stick with the recursive sequence expression. Any suggestion would expand my horizon.


// Create the zip function
let zipRec first second =
  let rec loop r xs ys = seq {
    if Seq.isEmpty xs || Seq.isEmpty ys then yield r
    else
      let r = Seq.append r (Seq.singleton((Seq.item 0 xs, Seq.item 0 ys)))
      yield! loop r (Seq.tail xs) (Seq.tail ys) }
  loop Seq.empty first second

// test
zipRec [1;2;3;4] [|"one"; "two" |] |&gt; List.ofSeq |&gt; printfn "%A"


What I don't like about my code:


It feels too imperative
I'm using a lot of the functions in the Seq module. Can this be written more F# idiomatic (short, concise, using more functional programming style)?
Does the code perform fast enough for real world scenarios? (I've used tail recursion)
Is the code robust enough (in regards to exceptions)?
Based upon my comment on that answer I've toyed a little to make a recursive sequence expression with roughly the same performance (on my computer at least) as Seq.zip

let zipRec (s1: _ seq) (s2: _ seq) =
  use e1 = s1.GetEnumerator ()
  use e2 = s2.GetEnumerator ()

  let rec loop hasMoved1 hasMoved2 = seq {
    if hasMoved1 &amp;&amp; hasMoved2 then
      yield e1.Current, e2.Current
      yield! loop (e1.MoveNext ()) (e2.MoveNext ())
  }

  loop (e1.MoveNext ()) (e2.MoveNext ())


without the recursive requirement it would be simpler this way

let zipRec (s1: _ seq) (s2: _ seq) = seq {
  use e1 = s1.GetEnumerator ()
  use e2 = s2.GetEnumerator ()

  while e1.MoveNext () &amp;&amp; e2.MoveNext () do
    yield e1.Current, e2.Current
}