【问题标题】:Can you list the contents of a namespace or module in F#你能在 F# 中列出命名空间或模块的内容吗
【发布时间】:2015-06-10 21:06:59
【问题描述】:

类似于this question about clojure,是否可以在 F# 中列出命名空间或模块的内容?当我为加载的 DLL 打开命名空间时,我没有收到命名空间不存在的错误,但是当我尝试使用记录的函数时,我看到命名空间不存在的错误。

我正在寻找一种列出值和方法的编程方式,而不是依赖于 IDE。例如,如果我加载了 F# repl,我正在寻找类似于:

> #r "mylib.DLL"
> open MyLib.Math
> list-namespace-content MyLib.Math;;
   val it : string = """
      MyLib.Math.Add : int -> int -> int
      MyLib.Math.TryDivide : int -> int -> int option
      MyLib.Math.Pi : float
   """

【问题讨论】:

  • 您能否提供有关错误的更多详细信息? (在 F# 中,当您在编辑器中使用 F# 绑定键入 List. 时,您可以看到模块中的所有函数,例如 List - 尽管您也可以使用反射从代码中列出它们)
  • 我的编辑器没有 F# 绑定。我正在寻找在repl中加载dll的情况。如果您通过#load 加载源文件,您将看到命名空间/模块内容的打印输出。但是如果你引用一个 dll 或者只是打开一个命名空间,你将看不到内容。
  • 只是出于好奇-您使用的是什么编辑器?有很多 F# 支持,包括 Emacs、vim、Atom、Sublime、Xamarin Studio(当然还有 VS)。
  • 我使用 vim,但我没有发现任何与操作系统/语言无关的处理标签。我使用许多不同的系统,但随身携带我的 vim 配置,所以我不能确定我在工作站上除了 vim 之外还有什么。
  • 我不是 vim 专家,但它有一个包:github.com/fsharp/vim-fsharp(但我很确定你至少需要单声道和一个可执行文件才能获得体面的 F# 经验vim)。

标签: f#


【解决方案1】:

据我所知,没有这样的函数可以做到这一点(我看过FSharpReflectionExtensions 模块),但您可以自己编写一个。所有的构建块都在那里。

虽然看起来很奇怪,但命名空间并不是 F#、C# 和 Visual Basic .NET 使用的 .NET 平台的一部分。在 IL 级别,类型只是 identified by name, culture, assembly, etc. 命名空间只是作为构成类型名称的字符串的第一部分出现。

但是,给定一个程序集,您可以列出其所有类型或所有公共类型。下面是后者的一个例子,考虑到我最近编写的一个 F# 程序集来做网球 kata:

> open System.Reflection;;
> let a = Assembly.LoadFrom @"<path>\Ploeh.Katas.Tennis.PropertyBased.dll";;

val a : Assembly =
  Ploeh.Katas.Tennis.PropertyBased, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

> let ts = a.GetExportedTypes();;

val ts : System.Type [] =
  [|Ploeh.Katas.PropertyBased.TennisProperties;
    Ploeh.Katas.PropertyBased.Tennis; Ploeh.Katas.PropertyBased.Tennis+Player;
    Ploeh.Katas.PropertyBased.Tennis+Player+Tags;
    Ploeh.Katas.PropertyBased.Tennis+Point;
    Ploeh.Katas.PropertyBased.Tennis+Point+Tags;
    Ploeh.Katas.PropertyBased.Tennis+PointsData;
    Ploeh.Katas.PropertyBased.Tennis+FortyData;
    Ploeh.Katas.PropertyBased.Tennis+Score;
    Ploeh.Katas.PropertyBased.Tennis+Score+Tags;
    Ploeh.Katas.PropertyBased.Tennis+Score+Points;
    Ploeh.Katas.PropertyBased.Tennis+Score+Forty;
    Ploeh.Katas.PropertyBased.Tennis+Score+Advantage;
    Ploeh.Katas.PropertyBased.Tennis+Score+Game|]

通过查看最后一个 . 左侧的字符串,您可以找到正在使用的命名空间 - 在本例中为 Ploeh.Katas.PropertyBased

但是,您应该知道命名空间可以跨越多个程序集。例如,System.Collections.Generic.List&lt;'T&gt;mscorlib 中定义,而System.Collections.Generic.Stack&lt;'T&gt;System 中定义。因此,使用上述反射只会为您提供在特定程序集中的命名空间中定义的成员

据我所知,F# 模块被编译为带有[&lt;CompilationMapping(SourceConstructFlags.Module)&gt;] 属性的静态类。这意味着您可以像这样列出模块:

> open Microsoft.FSharp.Core;;
> let modules =
    ts
    |> Array.filter
        (fun t -> t.GetCustomAttributes<CompilationMappingAttribute>()
                    |> Seq.exists (fun attr -> attr.SourceConstructFlags = SourceConstructFlags.Module));;

val modules : System.Type [] =
  [|Ploeh.Katas.PropertyBased.TennisProperties;
    Ploeh.Katas.PropertyBased.Tennis|]

如果你想列出Tennis模块中的所有函数,你可以这样做:

> let tm = modules |> Array.find (fun t -> t.Name = "Tennis");;

val tm : System.Type = Ploeh.Katas.PropertyBased.Tennis

> let functions = tm.GetMethods ();;

val functions : MethodInfo [] =
  [|Player other(Player);
    Microsoft.FSharp.Core.FSharpOption`1[Ploeh.Katas.PropertyBased.Tennis+Point] incrementPoint(Point);
    Point pointFor(Player, PointsData);
    PointsData pointTo(Player, Point, PointsData);
    Score scorePoints(Player, PointsData); Score scoreForty(Player, FortyData);
    Score scoreDeuce(Player); Score scoreAdvantage(Player, Player);
    Score scoreGame(Player); Score score(Score, Player); Score get_newGame();
    Score scoreSeq(System.Collections.Generic.IEnumerable`1[Ploeh.Katas.PropertyBased.Tennis+Player]);
    System.String pointToString(Point);
    System.String scoreToString(System.String, System.String, Score);
    System.String ToString(); Boolean Equals(System.Object);
    Int32 GetHashCode(); System.Type GetType()|]

您可能想要过滤掉一些继承的方法,例如ToStringGetHashCode

【讨论】:

    猜你喜欢
    • 2010-11-12
    • 1970-01-01
    • 2011-01-22
    • 2011-06-26
    • 2016-04-02
    • 1970-01-01
    • 2018-09-01
    • 1970-01-01
    • 2016-07-11
    相关资源
    最近更新 更多