F#interactive - 如何查看当前会话中定义的所有变量

use*_*081 10 f# f#-interactive

在F#interactive中,如何查看此会话中定义的变量/函数列表?像whos()python或ls()R中的函数一样?谢谢.

Tom*_*cek 17

您可以使用.NET Reflection实现此功能 - 局部变量和函数在单个动态程序集中定义为类型的静态属性/方法.您可以通过调用GetExecutingAssembly(在FSI本身中)获取该程序集,然后浏览类型以查找所有合适的属性.

以下是获取局部变量的合理工作函数:

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
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

> 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
Run Code Online (Sandbox Code Playgroud)

该函数返回"延迟"值(因为这是编写它的最简单的方法,而不预先读取所有变量的值会很慢),因此您需要使用该Value属性.还要注意你object回来了 - 因为F#类型系统无法知道类型 - 你必须动态地使用它.您可以通过迭代来获取所有名称vars...

  • 非常有用,但最好是`m.Name,(fun() - > m.GetValue(null,[||]))`而不是`m.Name,lazy m.GetValue(null,[| |])`..你要用`vars.["test1"]替换`值`.使用`vars.["test1"]()`并获得对可变对象的支持,因为仿函数每次都会进行评估. (2认同)

Ste*_*sen 7

我正在开发FsEye,它使用@Tomas技术的修改版本(过滤掉单位和函数值的变量并且只采用最新的it变量)在每次提交时获取所有FSI会话变量并在树中以可视方式显示它们以便您可以深入到他们的对象图.

你可以在这里看到我修改过的版本.