24

How to get 'System.Type' of the module?

For example module:

module Foo =
     let bar = 1

And this does not work:

printfn "%s" typeof<Foo>.Name

Error is:

The type 'Foo' is not defined
Mike Chaliy
  • 25,801
  • 18
  • 67
  • 105
  • 1
    Being inquisitive here. Why would you need to do this? You know the name of the module, Foo, and I don't think F# has the ability to pass modules as value. Thanks. – nlucaroni Feb 19 '10 at 15:16
  • The need is simple, I need some automation. I can do this with reflection. PowerPack.Metadata allows to iterate through modules, but may be there is something more easy. – Mike Chaliy Feb 19 '10 at 15:22
  • I need to do this also for an strongly typed API to a library I'm writing. – justin Feb 19 '10 at 16:10
  • Cross reference: [related question](http://stackoverflow.com/q/2916294) – Benjol Feb 05 '13 at 12:45

4 Answers4

39

You could add a marker type to the module and then discover the module's type from that:

module Foo =  
    type internal Marker = interface end
    let t = typeof<Marker>.DeclaringType
Phillip Trelford
  • 6,513
  • 25
  • 40
8

It would certainly be nice to have a moduleof operator... Since there's not one, the easiest way to do what you want is probably to use the Metadata library in the F# PowerPack:

#r "FSharp.PowerPack.Metadata.dll" 
open Microsoft.FSharp.Metadata

// get .NET assembly by filename or other means
let asm = ...

let fasm = FSharpAssembly.FromAssembly asm
let t = fasm.GetEntity("Foo").ReflectionType

Unfortunately, this won't work with dynamic assemblies (such as those generated via F# Interactive). You can do something similar using vanilla System.Reflection calls, but that's more dependent on having a good understanding of the compiled form that your module takes.

kvb
  • 54,864
  • 2
  • 91
  • 133
  • Main problem is that 'FSharpAssembly.FromAssembly asm' loads all types. Also reduce type safety. – Mike Chaliy Feb 19 '10 at 15:26
  • @Mike - I'm not sure what you mean by "reduce type safety"... There is no way to use a module as a generic type parameter, so you will have to use a string. This is unfortunate, but unavoidable. – kvb Feb 19 '10 at 17:46
  • 6
    does this still require a power pack to do or is there a better way 5 years later? – Maslow Nov 13 '15 at 16:31
  • Or 7 years later still – Aron Sep 12 '22 at 19:42
6

It can also be done using Quotations. First, define this helper function somewhere:

open Microsoft.FSharp.Quotations.Patterns

let getModuleType = function
| PropertyGet (_, propertyInfo, _) -> propertyInfo.DeclaringType
| _ -> failwith "Expression is no property."

Then, you can define a module and get its type like this:

module SomeName =
    let rec private moduleType = getModuleType <@ moduleType @>

Hope this helps.

Nikon the Third
  • 2,771
  • 24
  • 35
  • It does for me, although I modified the second part to: `module SomeName = let rec moduleType = getModuleType <@ moduleType @>;;`, then `SomeName.moduleType;;` should output the type information. – Nikon the Third Feb 23 '16 at 17:29
-2

module name is not a type.

List in List.map and let (a:List<int>) = [1;2;3] are different.

The first List is a module name, the second is a type.

Yin Zhu
  • 16,980
  • 13
  • 75
  • 117
  • 7
    I am concerned about 'FSharpType.IsModule(System.Type)', so module IS type, at least in CLR terms. – Mike Chaliy Feb 19 '10 at 15:24
  • 2
    The name of the static class (type) that the `List` module is compiled to is probably `ListModule`. – J D May 12 '16 at 23:18