2012-11-26 18 views
5

Buon pomeriggio, tutto!Esiste un modo sicuro per convertire una raccolta in una sequenza in F #?

Quindi ho giocato con i metodi per trasmettere una raccolta .NET a una struttura dati funzionale. Il meglio che ho potuto ottenere è di lanciarlo prima su un seq e su quello che voglio dopo.

Il problema è che questo sembra interrompere l'inferenza di tipo, che ovviamente non è sicura.

Esempio:

let a = new System.DirectoryServices.DirectorySearcher("<query>") in 
let entries = a.FindAll() 
let entries_list = 
    let (entries_seq : seq<obj>) = Seq.cast entries_list in 
    Seq.toList entries_Seq 
in 
entries_list (* list of AD objects found from query, has type obj *) 

Al fine di fare qualcosa di utile con entries_list, avrei dovuto fare:

entries_list :?> SearchResult 

Cercando di generalizzare a un ss < 'a> fallisce, in quanto il compilatore richiede ancora che io digiti staticamente il suo enumeratore (che ha senso).

C'è un modo per evitare questo? Sto iniziando a pensare che questo è un limite dell'utilizzo di strutture dati .NET in modo funzionale.

Scusate se questa è una domanda principiante; Sono verde a F # e programmazione funzionale in generale (e lo sto amando!). Saluti!

  • Carlos.
+0

Vuol fare 'lasciare entries_seq: ss <_> ...'lavoro - questo dovrebbe dare una sequenza fortemente tipizzata –

+0

no; Ottengo un errore di restrizione del valore, che è coerente con quello che stavo vedendo prima. –

risposta

11

Come dice Daniel, in genere non dovrebbe essere necessario utilizzare Seq.cast perché la maggior parte raccolte saranno già implementare l'interfaccia generica seq<'t>. Tuttavia, esistono diversi tipi di raccolta .NET che sono stati creati prima dell'introduzione di generici in .NET 2.0 che implementano solo l'interfaccia non generica IEnumerable. Il compilatore F # ha in effetti qualche logica speciale nei loop for chiamati "enumerable extraction" per rendere un po 'più facile lavorare su questi tipi di collezioni. Pertanto, se si sta solo che fare con uno di questi tipi di raccolta (ad esempio, si sta lavorando con DirectoryServices.SearchResultCollections molto), allora probabilmente ha senso per creare semplicemente una semplice funzione di supporto:

let typedSearchResults (s:SearchResultCollection) = 
    seq { for result in s -> result } 

che è quindi possibile utilizzare invece di Seq.cast per questo particolare tipo di raccolta.

Se stai usando un sacco di diverse collezioni vecchio stile nello stesso progetto, quindi è possibile utilizzare alcune # caratteristiche di fantasia F per fare un generico Seq.cast alternativa:

module Seq = 
    let inline inferCast s = 
     // constrain ^t to have an Item indexed property (which we don't actually invoke) 
     let _ = fun x -> (^t : (member Item : int -> ^v with get) (x, 0)) 
     let e = (^t : (member GetEnumerator : unit -> ^e) s) 
     seq { while (^e : (member MoveNext : unit -> bool) e) do 
       yield (^e : (member Current : obj) e) :?> ^v } 

Ora è possibile utilizzare Seq.inferCast invece di Seq.cast e il tipo di articolo corretto verrà dedotto per te. Questo è probabilmente eccessivo nel tuo caso, però.

+1

+1 Bel trucco, ma hai dimenticato "in linea". – Daniel

+0

@Daniel - grazie, risolto. – kvb

+0

In realtà potrebbe essere esattamente quello che sto cercando. Molte grazie! –

3

collezioni maggior NET implementano IEnumerable<T> (alias come seq<'T> in F #), ma di tanto in tanto si incorrerà attraverso uno che implementa solo l'interfaccia non generico IEnumerable. SearchResultCollection è uno di questi tipi. È possibile utilizzare Seq.cast per convertire tali raccolte in seq<'T>, consentendo di utilizzarle con le funzioni nel modulo Seq.

open System.DirectoryServices 

use searcher = new DirectorySearcher("<query>") 
let entries = searcher.FindAll() |> Seq.cast<SearchResult> 
let entries_list = Seq.toList entries 
+0

Grazie per la rapida risposta! Capisco molto, ma come faccio a generalizzare questo per tutte queste collezioni? Sembra che non riesca a fare un sacco di digitazione statica. Carlos –

+0

Vuoi 'Seq.cast' ma senza richiedere il tipo arg? Bene, in molti casi può essere dedotto dall'uso successivo della sequenza. kvb ha dato una soluzione interessante, ma anche alcune restrizioni. – Daniel

Problemi correlati