F #: a remoção de duplicatas de uma seq é lenta

Estou tentando escrever uma função que elimina duplicatas consecutivas, conforme determinado por uma determinada função de igualdade, de umseq<'a> mas com um toque: eu preciso doúltimo duplicar de uma execução de duplicatas para torná-lo na sequência resultante. Por exemplo, se eu tiver uma sequência[("a", 1); ("b", 2); ("b", 3); ("b", 4); ("c", 5)]e eu estou usandofun ((x1, y1),(x2, y2)) -> x1=x2 para verificar a igualdade, o resultado que eu quero ver é[("a", 1); ("b", 4); ("c", 5)]. O ponto desta função é que tenho pontos de dados chegando, onde às vezes os pontos de dados legitimamente têm o mesmo registro de data e hora, mas eu me preocupo apenas com o último, portanto, quero descartar os anteriores com o mesmo registro de data e hora. A função que eu implementei é a seguinte:

let rec dedupeTakingLast equalityFn prev s = seq {
     match ( Seq.isEmpty s ) with
     | true -> match prev with 
                 | None -> yield! s
                 | Some value -> yield value
     | false ->
         match prev with 
         | None -> yield! dedupeTakingLast equalityFn (Some (Seq.head s)) (Seq.tail s) 
         | Some prevValue -> 
             if not (equalityFn(prevValue, (Seq.head s))) then 
                 yield prevValue
             yield! dedupeTakingLast equalityFn (Some (Seq.head s)) (Seq.tail s)
}

Em termos de realmente fazer o trabalho, ele funciona:

> [("a", 1); ("b", 2); ("b", 3); ("b", 4); ("c", 5)] 
  |> dedupeTakingLast (fun ((x1, y1),(x2, y2)) -> x1=x2) None 
  |> List.ofSeq;;
val it : (string * int) list = [("a", 1); ("b", 4); ("c", 5)]

No entanto, em termos de desempenho, é um desastre:

> #time
List.init 1000 (fun _ -> 1) 
|> dedupeTakingLast (fun (x,y) -> x = y) None 
|> List.ofSeq
#time;;    
--> Timing now on    
Real: 00:00:09.958, CPU: 00:00:10.046, GC gen0: 54, gen1: 1, gen2: 1
val it : int list = [1]    
--> Timing now off

Claramente, estou fazendo algo muito idiota aqui, mas não consigo ver o que é. De onde vem o impacto no desempenho? Percebo que existem implementações melhores, mas estou especificamente interessado em entender por queesta implementação é tão lenta.

EDIT: FYI, conseguiu uma implementação decente no estilo funcional que se baseia emSeq. somente funções. O desempenho é bom, demorando cerca de 1,6x o tempo de implementação do estilo imperativo@gradbot abaixo que usa iteradores. Parece que a raiz do problema é o uso deSeq.head eSeq.tail em chamadas recursivas no meu esforço original.

let dedupeTakingLastSeq equalityFn s = 
    s 
    |> Seq.map Some
    |> fun x -> Seq.append x [None]
    |> Seq.pairwise
    |> Seq.map (fun (x,y) -> 
            match (x,y) with 
            | (Some a, Some b) -> (if (equalityFn a b) then None else Some a)  
            | (_,None) -> x
            | _ -> None )
    |> Seq.choose id

questionAnswers(8)

yourAnswerToTheQuestion