I'm new to F# and today I saw the member constraint feature of F#.
I was thinking of if one could (ab)use it in the following way...
Say I want to iterate get the texts of the items in a ListView. I could do it like this:
let listView = new System.Windows.Forms.ListView()
let itemTexts =
listView.Items
|> Seq.cast<System.Windows.Forms.ListViewItem>
|> Seq.map (fun item -> item.Text)
The Seq.cast above is not type safe and kind of ugly.
What I was thinking was this:
> let item (i:int) = listView.Items.Item i;;
val item : int -> System.Windows.Forms.ListViewItem
So the type of the IEnumerable
is in fact encoded into the class, just in a round-about way.
The example of member constraints I saw was the following:
type Cat() =
member this.Walk() = printfn "cat walk"
type Dog() =
member this.Walk() = printfn "dog walk"
let adapter() =
let cat = Cat()
let dog = Dog()
let inline walk (x : ^T) = (^T : (member Walk : unit->unit) (x))
walk(cat)
walk(dog)
I got the idea that it's a bit similar to what I'd want to do above.
Could this be used to create a function to be use like the following instead?
let itemTexts =
listView.Items
|> Seq.asSeq
|> Seq.map (fun item -> item.Text)
Edit : The idea was to implement a general Seq.asSeq
extension method that'd take something that implements the non-generic IEnumerable
and that has a strongly typed Item
-member as above and then invoke Seq.cast
with the corresponding type from the Item
-member.
Here's my first fumbling attempts:
let listView = new System.Windows.Forms.ListView()
let items =
listView.Items
type cat() =
member this.Item (i:int) = "cat walk"
interface System.Collections.IEnumerable with
member this.GetEnumerator() = ((seq { yield (this.Item 0) }) :> System.Collections.IEnumerable).GetEnumerator()
type dog() =
member this.Item (i:int) = 6
interface System.Collections.IEnumerable with
member this.GetEnumerator() = ((seq { yield (this.Item 0) }) :> System.Collections.IEnumerable).GetEnumerator()
let cat = cat()
let dog = dog()
let inline asSeq (x : ^t) =
let dummy _ = (^t : (member Item : int -> 'a) (x, 0))
Seq.cast<'a> x
This almost works, but not for the real type!
> cat;;
val it : cat = seq ["cat walk"]
> asSeq cat;;
val it : seq<string> = seq ["cat walk"]
> asSeq dog;;
val it : seq<int> = seq [6]
> asSeq items;;
asSeq items;;
------^^^^^
C:\...\stdin(5,7): error FS0001: The type 'System.Windows.Forms.ListView.ListViewItemCollection' does not support any operators named 'Item'
>
I guess it's my fake-types that do not properly reflect the .NET indexed properties...
Any help?
Edit 2: This actually works!
let inline asSeq (x : ^t) =
let dummy _ = (^t : (member Item : int -> 'a with get) (x, 0))
Seq.cast<'a> x
It sounds like you want something along these lines , in which case your code is nearly right.
Note that one issue is that you're attempting to use indexed properties interchangeably with methods, but you're not doing it quite right: for an indexed property named Item
, the method's actual name will be get_Item
(alternatively, you can use the syntax member Item : int -> 'a with get
instead of using the get_Item
method directly).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.