Interested in the question of how to get information about the functions that the module contains. I want to get something like what FSI issues.

For example for the following module

module Test = let ign _ = () let getNowDateTime() = System.DateTime.Now let getNumbers count = [1..count] 

FSI displays this information.

 module Test = begin val ign : 'a -> unit val getNowDateTime : unit -> System.DateTime val getNumbers : count:int -> int list end 

I tried to get the data through reflection as follows.

 let getInfoAboutModule (t : Type) = let genericToString (t : Type) = match t.GenericTypeArguments with | [| |] -> t.FullName | x -> x |> Seq.map (fun x -> x.Name) |> String.concat "," |> sprintf "%s<%s>" t.Name let getInfo (mi:MethodInfo) = let parameter = let sb = System.Text.StringBuilder() for x in mi.GetParameters() do x.ParameterType |> genericToString |> sprintf "%s : %s ->" x.Name |> sb.Append |> ignore sb.ToString() |> fun str -> if str |> System.String.IsNullOrEmpty then "unit -> " else str sprintf "%s : %s %s" mi.Name parameter (genericToString mi.ReturnType) t.GetMethods(BindingFlags.Public ||| BindingFlags.Static) |> Seq.map getInfo 

for the Test module, the result will be as follows

 ign : _arg1 : -> System.Void getNowDateTime : unit -> System.DateTime getNumbers : count : System.Int32 -> FSharpList`1<Int32> 

MCVE (ideone)

but, naturally, so I receive names far from F # -s.


PS It is impossible to add any attributes to the module, since you need to leave the ability to extract data from modules from other assemblies.

  • one
    Well, as if yes, the names of the types are given from the point of view of the BCL, which does not know about F # aliases (as well as about C # aliases). Perhaps you need to build an explicit match table. - VladD
  • @VladD Yeah, I'll try to look for more options - maybe there is some workaround - Ev_Hyper

1 answer 1

You can use FSharp.Compiler.Service to analyze the source code of the modules. If the module is compiled and its source is not, then I doubt that you can achieve a better result than yours.

Based on this example:

 open System open System.IO open Microsoft.FSharp.Compiler.SourceCodeServices let text = """ module Test = let ign _ = () let getNowDateTime() = System.DateTime.Now let getNumbers count = [1..count] """ let checker = FSharpChecker.Create() // ΠΈΠ· ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° let parseAndTypeCheckSingleFile input = let file = "test.fsx" let projOptions = checker.GetProjectOptionsFromScript(file, input) |> Async.RunSynchronously let parseFileResults, checkFileResults = checker.ParseAndCheckFileInProject(file, 0, input, projOptions) |> Async.RunSynchronously // Wait until type checking succeeds (or 100 attempts) match checkFileResults with | FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res | res -> failwithf "Parsing did not finish... (%A)" res // ΠΏΠ΅Ρ‡Π°Ρ‚ΡŒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ Ρ‡Π»Π΅Π½Π΅ модуля let printInfo (fn:FSharpMemberOrFunctionOrValue) = // строка с ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ ΠΎ Ρ‚ΠΈΠΏΠ΅ let rec getTypeString (t:FSharpType) = if t.HasTypeDefinition then let prms = [ for x in t.GenericArguments -> (getTypeString x) ] in t.TypeDefinition.DisplayName + " " + String.Join(" ", prms) else t.ToString() printf "%s: " fn.DisplayName for group in fn.CurriedParameterGroups do for prm in group do match prm.Name with | None -> () | Some name -> printf "%s:" name printf "%s -> " (getTypeString prm.Type) printf "%s\n" (getTypeString fn.ReturnParameter.Type) [<EntryPoint>] let main argv = let parseFileResults, checkFileResults = parseAndTypeCheckSingleFile text let m = checkFileResults.PartialAssemblySignature.Entities.[0] let fns = m.NestedEntities.[0].MembersFunctionsAndValues for x in fns do printInfo x 0 

Result:

 ign: type 'a -> unit getNowDateTime: unit -> DateTime getNumbers: count:int -> list int 

Or you can study the source directly FSI .


If an error occurs during parsing, you need to copy the files FSharp.Core.optdata and FSharp.Core.sigdata to the program directory. Files can be found in %PROFRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.4.0.0\ .

  • Thanks for the answer, but yes, the module is compiled and there is no access to the source code directly. - Ev_Hyper
  • @Ev_Hyper then you really have to build some kind of correspondence table FSharpList``1<Int32> - list int , etc. - kmv
  • @FoggyFinder F # in real development, alas, was not possible to use. I'm rather just a curious person. - kmv
  • one
    @FoggyFinder I updated the answer, the reason is the absence of a pair of files - kmv