kam
kam

Reputation: 669

F# type constraints indexable

I'm trying to make a type that should represent a "slice" of some indexable collection.

I know that there are some similar types in F# but not one that specifies the criteria that I need.

To do this it needs to carry a reference to the collection of type 'content and the content needs to be indexable. So I tried this constraint since a type only needs to have the member Item (get/set) so I tried this

type Slice<'a, 'content when 'content: (member Item: int -> 'a)>

This still throw the usual error

So is it possible to constrain a type to still be generic but constraint to be indexable?

Upvotes: 1

Views: 86

Answers (2)

Brian Berns
Brian Berns

Reputation: 17038

I think something like this should work:

type Slice<'a, 'content when 'content: (member get_Item: int -> 'a)> =
    {
        Content : 'content
        Start : int
        Stop : int
    }
    with
    member inline slice.get_Item(i) =
        slice.Content.get_Item(slice.Start + i)

I've implemented get_Item on Slice as well, so you can take a slice of a slice. Here are some values of this type:

let strSlice =
    {
        Content = "hello"
        Start = 1
        Stop = 2
    }

let arraySlice =
    {
        Content = [| 2; 4; 6; 8 |]
        Start = 0
        Stop = 3
    }

let strSliceSlice =
    {
        Content = strSlice
        Start = 0
        Stop = 1
    }

Upvotes: 2

kam
kam

Reputation: 669

[<Interface>]
type Indexable<'a> =
    abstract member Item: int -> 'a with get

[<Struct>]
type Slice<'a> =
    {
       content: Indexable<'a>
       start: int
       len: int
    }
with
    interface Indexable<'a> with
        member I.Item with get(i) = I.[idx]

    member S.Item with get(idx) = 
         if idx >= S.len 
         then raise(IndexOutOfRangeException()) 
         else S.content.[S.start+idx]

 

This works.

Upvotes: 0

Related Questions