Impossible to make object with a recursive type constraint?
Asked Answered
U

2

6

This is a purely academic question, but riffing off of this question about type constraints. The questioner gave this as an example:

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

which f# happily compiles. Now the problem is how do you make this object??

let z = new Something<???, ???>()
Unemployable answered 1/6, 2016 at 20:50 Comment(4)
See msdn.microsoft.com/en-us/library/… for a non-contrived example of a class that could be used.Satellite
Maybe you should change the title to remove the word Impossible, try Can't get my head around this oneYusuk
@Satellite You're right. let z = new Something<OpenXmlElement, OpenXmlElement>() worksUnemployable
@Guy. For sure. I was thinking new Something<string, seq<string>>() ... which won't work.Unemployable
A
3

Here's one way:

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

Instead of returning the empty sequence, you could implement this class to return a sequence of child nodes. I called this type Node<'a>, because it's a fairly idiomatic way to model a tree (or a graph) in C#.

Use:

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

> smth.x;;
val it : int = 42
Andorra answered 1/6, 2016 at 21:11 Comment(0)
S
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>()
Satellite answered 1/6, 2016 at 21:11 Comment(0)
A
3

Here's one way:

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

Instead of returning the empty sequence, you could implement this class to return a sequence of child nodes. I called this type Node<'a>, because it's a fairly idiomatic way to model a tree (or a graph) in C#.

Use:

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

> smth.x;;
val it : int = 42
Andorra answered 1/6, 2016 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.