F#交互式环境 - 如何查看当前会话中定义的所有变量

10
在 F# 交互中,我如何查看此会话中定义的变量/函数列表?类似于 Python 中的函数 whos() 或 R 中的 ls()?谢谢。
3个回答

17
您可以使用.NET反射来实现这一点-本地变量和函数被定义为单个动态程序集中类型的静态属性/方法。您可以通过调用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

这是一个例子:
> 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

该函数返回“懒惰”的值(因为这是最简单的方法,而不需要预先读取所有变量的值,这样会很慢),因此您需要使用Value 属性。另请注意,您得到的是对象 - 因为F#类型系统无法知道类型 - 您必须动态使用它。您可以通过迭代vars 来获取所有名称...

当我运行上面的代码时,我得到了很多it在变量中:Microsoft.FSharp.Collections.FSharpList1[System.Reflection.PropertyInfo] it`,这是什么以及如何过滤掉它?谢谢。 - user 9081
是的,“it”是由F#交互自动生成的(您可以看到在输出中也打印了“it”,并且您可以使用该变量获取最后的结果)。您可以过滤它们或只取最后一个... - Tomas Petricek
哇,Thomas,你真是个天才。顺便说一下,我正在从你和Jon的书中学习F#,我很喜欢它 :) 做得好。有没有写另一本书的计划?如果有的话,坚持与Manning合作,他们是一个伟大的出版商(至少在我的角度上是这样)。 - Martin Doms
2
非常实用,但是最好使用 m.Name , (fun () -> m.GetValue(null, [||])) 而不是 m.Name, lazy m.GetValue(null, [||])。你可以将 vars.["test1"].Value 替换为 vars.["test1"]() 并获得对可变对象的支持,因为每次都会评估函数。 - Steve Channell
@TomasPetricek 这个方法似乎在最新版本(无论是 FSharp.Compiler.Service 还是 net6.0)中不起作用。有什么想法/建议吗?这个方法一度非常有效... - Roman Kuzmin

8
我正在开发FsEye,它使用修改版的@Tomas技术(过滤掉单位和函数值变量,并仅获取最新的it变量)在每次提交时抓取所有FSI会话变量,并以树形式直观地显示它们,这样您就可以深入了解它们的对象图。

您可以在这里看到我的修改版本。


哈哈,我一直在考虑做类似的事情,看起来这正是我所需要的!我会尝试一下,从外观上看,工作得很棒! - gjvdkamp
很高兴听到这个消息!一开始只是一个小小的个人工具,但随着不断完善,我意识到很多其他人可能也在寻找同样的东西,所以我将其打磨完善并发布了出来。 - Stephen Swensen

2
很抱歉,目前FSI无法实现此功能。

连自定义函数都不能写吗? - user 9081

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接