It's easier to show on example. If I send the following to F# interactive
type Person = {Name : string; Age : int}
let joe = {Name = "Joe"; Age=30}
The output is:
type Person =
{Name: string;
Age: int;}
val joe : Person = {Name = "Joe";
Age = 30;}
Fsi is smart enough to print all the properties.
Sending the following, line-by-line
let l = new List<int>()
l
results in
val l : List<int>
val it : List<int> = seq []
Fsi sees that l implements IEnumerable, and (rightfully) thinks this is what I expect to see. But there are other properties in l, notably Count and Capacity. (That's not that important for lists, but it is for complex types in my case)
How do I make F# interactive print out the properties of an object and ignore it being IEnumerable? (just like for the type Person in the first example)
You can provide a custom printer using fsi.AddPrinter. It takes a function that specifies how to format a specific type - I don't think there is an easy way to do this generically, but you can use non-generic IEnumerable in this case. The following prints the sequence using the default printing and adds Count:
fsi.AddPrinter(fun (en:System.Collections.IEnumerable) ->
let count = Seq.cast<obj> en |> Seq.length
sprintf "%A { Count = %d }" en count
)
For example:
> l;;
val it : List<int> = seq [] { Count = 0 }
> seq { 1 .. 100000 };;
val it : seq<int> = seq [1; 2; 3; 4; ...] { Count = 100000 }
Funnily enough, this also changes printing for strings, but you could avoid that by adding the custom properties only when en value is not of type string.
> "hello";;
val it : string = "hello" { Count = 5 }
If you override the .ToString method, fsi will use that instead. You can also use the
[<StructuredFormatDisplay>] attribute if only want to affect FSI
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With