Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Interactive - how to make it print properties of an object, when the latter is enumerable

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)

like image 954
bohdan_trotsenko Avatar asked Jan 13 '23 14:01

bohdan_trotsenko


2 Answers

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 }
like image 154
Tomas Petricek Avatar answered Jan 21 '23 02:01

Tomas Petricek


If you override the .ToString method, fsi will use that instead. You can also use the [<StructuredFormatDisplay>] attribute if only want to affect FSI

like image 42
Gustavo Guerra Avatar answered Jan 21 '23 01:01

Gustavo Guerra