2016-06-01 47 views
6

Questa è una domanda puramente accademica, ma riffing di this question sui vincoli di tipo. L'intervistatore ha fornito questo esempio:Impossibile rendere l'oggetto con un vincolo di tipo ricorsivo?

type Something<'a, 'b when 'b :> seq<'b>>() = 
    member __.x = 42 

che f # compila felicemente. Ora il problema è come si costruisce questo oggetto ??

let z = new Something<???, ???>() 
+3

Vedi https://msdn.microsoft.com/en-us/library/documentformat.openxml.openxmlelement(v=office.14).aspx per esemplificativo e non artificiosa di una classe che potrebbe essere utilizzata. – kvb

+1

Forse dovresti cambiare il titolo per rimuovere la parola "Impossibile", prova "Non riesco a capirci questo" –

+0

@kvb Hai ragione. 'let z = new Something ()' funziona – Ray

risposta

3

Ecco un modo:

open System.Collections.Generic 

type Node<'a>() = 
    let getEmptyEnumerator() = Seq.empty<Node<'a>>.GetEnumerator() 
    interface IEnumerable<Node<'a>> with 
     member this.GetEnumerator() = getEmptyEnumerator() 
     member this.GetEnumerator() = 
      getEmptyEnumerator() :> System.Collections.IEnumerator 

Invece di restituire la sequenza vuota, è possibile implementare questa classe per restituire una sequenza di nodi figlio. Ho chiamato questo tipo Node<'a>, perché è un modo abbastanza idiomatico di modellare un albero (o un grafico) in C#.

Usa:

> let smth = Something<string, Node<int>>();;  
val smth : Something<string,Node<int>> 

> smth.x;; 
val it : int = 42 
4
type T() = 
    interface seq<T> with 
     member this.GetEnumerator() = ([] :> seq<T>).GetEnumerator() 
     member this.GetEnumerator() = ([] :> seq<T>).GetEnumerator() :> System.Collections.IEnumerator 

let z = new Something<string, T>()