F#类型提供程序 - “仅返回生成的类型”

时间:2011-09-17 21:44:11

标签: f# type-providers

尝试使用类型提供程序对类型级别的peano数进行编码:

namespace TypeProviderPlayground

open System
open Microsoft.FSharp.Core.CompilerServices
open System.Runtime.CompilerServices

[<assembly: TypeProviderAssembly()>]
do()

type Z = class end
type 'a S = class end
type N = class end

[<TypeProvider>]
type PeanoProvider(s: TypeProviderConfig) =
    let invalidate = Event<_,_>()
    interface ITypeProvider with
        member x.ApplyStaticArguments(typeWithoutArguments, typeNameWithArguments, staticArguments) =
            let n : int = unbox staticArguments.[0]
            [1..n] |> List.fold (fun s _ -> typedefof<S<_>>.MakeGenericType [| s |]) typeof<Z>
        member x.GetNamespaces() = 
            let ns = 
                { new IProvidedNamespace with
                    member x.GetNestedNamespaces() = [||]
                    member x.GetTypes() = [||]
                    member x.ResolveTypeName t =
                        if t = "N"
                            then typeof<N>
                            else null
                    member x.NamespaceName = "Peano" }
            [| ns |]
        member x.GetStaticParameters t =
            let p = 
                { new Reflection.ParameterInfo() with
                    member z.Name = "number"
                    member z.ParameterType = typeof<int> }
            [| p |]

        [<CLIEvent>]
        member x.Invalidate = invalidate.Publish
        member x.Dispose() = ()
        member x.GetInvokerExpression(syntheticMethodBase, parameters) = 
            raise <| NotImplementedException()

N类型只是一个虚拟,否则我无法通过类型提供程序。 消费者代码:

open TypeProviderPlayground

[<Generate>]
type S<'a> = Peano.N<5>

我收到了这个错误:

error FS3152: The provider 'TypeProviderPlayground.PeanoProvider' returned a non-generated type
'TypeProviderPlayground.S`1[[TypeProviderPlayground.S`1[[TypeProviderPlayground.S`1[[TypeProviderPlayground.S`1[[TypeProviderPlayground.S`1[[TypeProviderPlayground.Z, TypeProviderPlayground, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], TypeProviderPlayground, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], TypeProviderPlayground, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], TypeProviderPlayground, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], TypeProviderPlayground, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]' 
in the context of a [<Generate>] declaration. Either remove the [<Generate>] declaration or adjust the type provider to only return generated types. 

其中说该类型已正确构造(Z S S S S S)但由于某种原因,编译器不会将其接受为“生成类型”。

如果我删除[<Generated>]属性,我会收到一些其他错误,告诉我要添加它。

这是否意味着类型提供程序只能处理动态发出的类型(这在乍一看似乎是一个奇怪的要求)?

另外,如果我这样做:

[<Generate>]
type WW<'a> = Peano.N<5>

我收到错误消息,指出WW'1是预期的,但返回了S'1。为什么返回的类型(由类型提供者)必须匹配我在使用者中声明的类型名称?

2 个答案:

答案 0 :(得分:15)

有关类型提供程序的一些重要事项需要实现。首先,提供的类型有两种:

  1. 生成的类型是嵌入到使用类型提供程序的程序集中的真实.NET类型(这是包装代码生成工具的类型提供程序,如sqlmetal使用)
  2. Erased types 是模拟类型,在编译代码时由其他类型表示。
  3. 正如单挑一样,控制这种区别的机制仍然悬而未决。在预览中,您需要使用嵌入了生成类型的程序集中的[<Generate>]属性,并且在使用已擦除的提供类型时不应使用[<Generate>]属性。我相信(但不能记得肯定)在提供的结束时生成的内容是根据类型的Assembly属性确定的。

    另外,请注意,在实施API时,您不一定要使用实际类型(例如,通过typeof<X>) - 您经常需要使用从System.Type派生的自定义类型。在不同的方法中必须满足许多不变量。原始类型提供程序API不容易使用 - 我建议等待一些使用更好的API包装器的示例(我希望在未来几周内发布)。

    话虽如此,从这里快速看一下,你现在的方法中至少有一些东西对我来说是错误的:

    1. 您从ApplyStaticArguments返回的类型与参数typeNameWithArguments的名称不同。大概这就是为什么你得到提到类型名称的错误。
    2. 您正在尝试使用类型缩写,该缩写从非泛型类型(例如WW<'a>)创建泛型类型(例如S<S<S<S<S<Z>>>>>)。

答案 1 :(得分:4)

忘了对此进行更新:确实缺少的是“删除了”#39;在我的导出&#39;中键入标记(TypeProviderTypeAttributes.IsErased)类型。我把experiments on github