Custom F # Type Provider: Container Type Already Installed Error

I recently visited Keith Battochi's tutorial on type providers, in which he introduced a variant of the type provider MiniCsv in the MSDN tutorial. Unfortunately, my laptop was not available, so I had to write the code manually as I could. I believe that I recreated the type provider, but I get

error FS3033: The type provider 'CsvFileTypeProvider+CsvFileTypeProvider' reported an error: container type for 'CsvFileProvider.Row' was already set to 'CsvFileProvider.CsvFile,Filename="events.csv" 

When I look at the code, I don’t see how I add the Row type to the container (or to another container) twice. Deleting selected lines of code does not help.

This is how I call the code in fsi:

 #r "CsvFileTypeProvider.dll" open CsvFileProvider let eventInfos = new CsvFile<"events.csv">() ;; 

And here is the code itself:

 module CsvFileTypeProvider open Samples.FSharp.ProvidedTypes open Microsoft.FSharp.Core.CompilerServices let getType str = if System.DateTime.TryParse(str, ref Unchecked.defaultof<_>) then typeof<System.DateTime>, (fun (str:Quotations.Expr) -> <@@ System.DateTime.Parse(%%str) @@>) elif System.Int32.TryParse(str, ref Unchecked.defaultof<_>) then typeof<System.Int32>, (fun (str:Quotations.Expr) -> <@@ System.Int32.Parse(%%str) @@>) elif System.Double.TryParse(str, ref Unchecked.defaultof<_>) then typeof<System.Double>, (fun (str:Quotations.Expr) -> <@@ System.Double.Parse(%%str) @@>) else typeof<string>, (fun (str:Quotations.Expr) -> <@@ %%str @@>) [<TypeProvider>] type CsvFileTypeProvider() = inherit TypeProviderForNamespaces() let asm = typeof<CsvFileTypeProvider>.Assembly let ns = "CsvFileProvider" let csvFileProviderType = ProvidedTypeDefinition(asm, ns, "CsvFile", None) let parameters = [ProvidedStaticParameter("Filename", typeof<string>)] do csvFileProviderType.DefineStaticParameters(parameters, fun tyName [| :? string as filename |] -> let rowType = ProvidedTypeDefinition(asm, ns, "Row", Some(typeof<string[]>)) let lines = System.IO.File.ReadLines(filename) |> Seq.map (fun line -> line.Split(',')) let columnNames = lines |> Seq.nth 0 let resultTypes = lines |> Seq.nth 1 |> Array.map getType for idx in 0 .. (columnNames.Length - 1) do let col = columnNames.[idx] let ty, converter = resultTypes.[idx] let prop = ProvidedProperty(col, ty) prop.GetterCode <- fun [row] -> converter <@@ (%%row:string[]).[idx] @@> rowType.AddMember(prop) let wholeFileType = ProvidedTypeDefinition(asm, ns, tyName, Some(typedefof<seq<_>>.MakeGenericType(rowType))) wholeFileType.AddMember(rowType) let ctor = ProvidedConstructor(parameters = []) // the *type* is parameterized but the *constructor* gets no args ctor.InvokeCode <- //given the inputs, what will we get as the outputs? Now we want to read the *data*, skip the header fun [] -> <@@ System.IO.File.ReadLines(filename) |> Seq.skip 1 |> Seq.map (fun line -> line.Split(',')) @@> wholeFileType.AddMember(ctor) wholeFileType ) do base.AddNamespace(ns, [csvFileProviderType]) [<TypeProviderAssembly>] do() 

Thanks for any help!

+6
source share
1 answer

you need to use a different constructor when defining a "Row" type. The existing ProvidedTypeDefinition type provides two constructors:

  • (assembly, namespace, type-name, base type) - defines the top-level type, the container of which is the namespace.
  • (typename, basetype) - defines a nested type that should be added to another type.

Now the Row type is defined using the first constructor, so it is considered as a top level type. An exception occurs when this type is later added to wholeFileType as nested.

+6
source

Source: https://habr.com/ru/post/918826/


All Articles