FSharp.TypeProviders.SDK
FSharp.TypeProviders.SDK copied to clipboard
Emit Discriminated Unions
I'm currently playing around with building a DSL for Avalonia UI. I looked at how Fabulous generates types one time.
It would be interesting to create the DSL dynamically using a (generative) type provider. In my case I would like to generate DU's for all implementations of IControl.
type ButtonAttr =
| Name of string
| Width of float
…
This would make it extremely simple to use 3rd party controls, because bindings are generated at compile/ design time.
Currently it is (as far as I know) not possible to emit F# specific types like Records or Discriminated Unions from a Type Provider.
- Why isn't it possible to generate F# specific types (aren't they just nested classes with custom attributes/metadata after all) ?
- Is there a general interest in making this possible (or is it just me wanting this) ?
EDIT: just found out there is a discussion about using a TP in Fabulous
There is a language suggestion regarding provided DU & records: https://github.com/fsharp/fslang-suggestions/issues/154
And another one to be able to pass types to type providers: https://github.com/fsharp/fslang-suggestions/issues/212
- Why isn't it possible to generate F# specific types (aren't they just nested classes with custom attributes/metadata after all) ?
The main thing is that it's just a lot of work. The way TPs are architected (providing .NET System.Type/MethodInfo etc. and the compiler converts them to F# TAST nodes) effectively means we have to fully invert the compilation process from .NET IL types --> F# TAST types. This is implemented in tast.fs and infos.fs in the F# compiler for methods, types, properties, events but there is no corresponding inversion for F#-defined union/record types.
The inversion would be similar to that implemented in FSharp.Reflection.FSharpType/FSharpValue based on the attributes etc. But it's painful to implement and fully test accurately.
- Is there a general interest in making this possible (or is it just me wanting this) ?
Yes, people are interested in this
@dsyme Thank you for the explanation (If you don't mind I have on further question).
If generating TAST in F# would be simple enough, the TAST could be given straight to the Compiler, then compilation could happen as usual. Why is it the other way around (Type/MethodInfo -> TAST) ?
If generating TAST in F# would be simple enough, the TAST could be given straight to the Compiler, then compilation could happen as usual. Why is it the other way around (Type/MethodInfo -> TAST) ?
The TAST is an internal compiler representation and not deemed to be sufficiently stable nor simple enough to allow direct generation.
Thanks for the explanation, should I close this now ?
@JaggerJo It's ok to leave it open I think
What about providing the FSharp compiler services interface to a TypeProvider, so it can get better metadata?
And with ProvidedDU and ProvidedRecords, that would increase the flexibility.
Perhaps we could have a DSL for creating the relevant part of the TypeProvider output that will become the TAST. (of course you wouldn't expose the real TAST)
I don't mind it being internally represented by Type/MethodInfo, but wouldn't it be simpler having a specific AST/DSL for TypeProviders ? (nothing impedes someone doing that and it creating the Quotation expressions needed, that's precisely how I'm thinking to tackle my TypeProvider )
[edit: after reading other topics, I guess I have my historical reasons answer]
But FSharpCompilerServiceTypeProvider, that would be a fun thing !