i was wondering if it's possible to generate a something similar to a simple type provider (Record or Union, with no members, just the matching name with the string name) from a string, at compile time.
mixing this
http://www.readcopyupdate.com/blog/2014/09/18/faking-typeclasses-using-static-type-constraints.html
and this
Create Discriminated Union Case from String
or a similar approach to record types.
what i would like to obtain in, for example (not necessarily with the same approach):
[<Literal>]
let myTypeName = "One"
type SingleStringTypeProvider = ... (here implementation)
type Provided = SingleStringTypeProvider<singleString>
let typeName = typeof<Provided.One>.Name
final result: One is a Type at compile time (and not a method nor a function)
As suggested in the first answer (thanks a lot : )), I have tried to implement it with type provided, but i am still struggling when trying to access the type provider from my script file, apparently i see only the created type but non the type provider itself?
module SimpleStringProvider
open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
[<TypeProvider>]
type SingleStringTypeProvider (config : TypeProviderConfig) as this =
inherit TypeProviderForNamespaces (config)
let asm = System.Reflection.Assembly.GetExecutingAssembly()
let ns = "SimpleStringProvider"
let stringProvider = ProvidedTypeDefinition(asm, ns, "SingleStringTypeProvider", Some(typeof<obj>))
// Define one static parameter with type name
let parameter = ProvidedStaticParameter("TypeName", typeof<string>)
do stringProvider.DefineStaticParameters([parameter], fun typeName args ->
// Create the main type (this corresponds to `Provided`)
let resTy = ProvidedTypeDefinition(asm, ns, typeName, Some(typeof<obj>))
// Add a nested type as a member using the name from the parameter
let typeName = args.[0] :?> string
ProvidedTypeDefinition(typeName, None)
|> resTy.AddMember
resTy )
[<assembly:TypeProviderAssembly>]
do ()
and here is the code in my script.fsx file, probably i am making some silly mistakes i guess.
#r @".\testType\SimpleStringProvider.dll"
open SimpleStringProvider
type x = SimpleStringProvider.SingleStringTypeProvider<"test">
ERROR in script.fsx file
The non-generic type 'SimpleStringProvider.SingleStringTypeProvider' does not expect any type arguments, but here is given 1 type argument(s)
You can provide nested types and those can be based on the static parameter. In your example Provided is a type and Provided.One can be a nested type.
To do this, you can write something like this:
[<TypeProvider>]
type public SingleStringTypeProvider(cfg:TypeProviderConfig) as this =
inherit TypeProviderForNamespaces()
// Generate namespace and the main type provider
let asm = System.Reflection.Assembly.GetExecutingAssembly()
let ns = "Samples"
let stringProvider = ProvidedTypeDefinition(asm, ns, "SingleStringTypeProvider", Some(typeof<obj>))
// Define one static parameter with type name
let parameter = ProvidedStaticParameter("TypeName", typeof<string>)
do stringProvider.DefineStaticParameters([parameter], fun typeName args ->
// Create the main type (this corresponds to `Provided`)
let resTy = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<IniFile>)
// Add a nested type as a member using the name from the parameter
let typeName = args.[0] :?> string
ProvidedTypeDefinition(typeName, None)
|> resTy.AddMember
resTy )
[<assembly:TypeProviderAssembly>]
do()
I have not tested this, so you might need to do some tweaking, but I think it should work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With