Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# interactive - how to see all the variables defined in current session

In F# interactive, how can I see a list of variables/functions defined in this session? Like a function whos() in python or ls() in R? Thanks.

like image 753
user 9081 Avatar asked Feb 14 '11 20:02

user 9081


2 Answers

I'm developing FsEye, which uses a modified version of @Tomas' technique (filters out unit and function valued vars and only takes the latest it var) to grab all FSI session variables upon each submission and displays them visually in a tree so that you can drill down into their object graphs.

You can see my modified version here.

like image 135
Stephen Swensen Avatar answered Sep 28 '22 00:09

Stephen Swensen


You can probably implement this using .NET Reflection - local variables and functions are defined as static properties/methods of types in a single dynamic assembly. You can get that assembly by calling GetExecutingAssembly (in FSI itself) and then browse the types to find all suitable properties.

The following is a reasonably working function for getting local variables:

open System.Reflection
open System.Collections.Generic

let getVariables() = 
  let types = Assembly.GetExecutingAssembly().GetTypes()
  [ for t in types |> Seq.sortBy (fun t -> t.Name) do
      if t.Name.StartsWith("FSI_") then 
        let flags = BindingFlags.Static ||| BindingFlags.NonPublic |||
                    BindingFlags.Public
        for m in t.GetProperties(flags) do 
          yield m.Name, lazy m.GetValue(null, [||]) ] |> dict

Here is an example:

> let test1 = "Hello world";;
val test1 : string = "Hello world"

> let test2 = 42;;
val test2 : int = 42

> let vars = getVariables();;
val vars : System.Collections.Generic.IDictionary<string,Lazy<obj>>

> vars.["test1"].Value;;
val it : obj = "Hello world"

> vars.["test2"].Value;;
val it : obj = 42

The function returns "lazy" value back (because this was the simplest way to write it without reading values of all variables in advance which would be slow), so you need to use the Value property. Also note that you get object back - because there is no way the F# type system could know the type - you'll have to use it dynamically. You can get all names just by iterating over vars...

like image 43
Tomas Petricek Avatar answered Sep 28 '22 00:09

Tomas Petricek