F#类型提供程序-“仅返回生成的类型" [英] F# type provider - "only return generated types"

查看:71
本文介绍了F#类型提供程序-“仅返回生成的类型"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Trying to encode type-level peano numbers using a type provider:

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类型只是一个虚拟对象,否则我无法使它通过类型提供程序. 消费者代码:

The N type is just a dummy, otherwise I couldn't get it to go through the type provider. Consumer code:

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),但是出于某种原因,编译器不会将其接受为生成的类型".

Which says that the type was correctly constructed (Z S S S S S) but for some reason the compiler won't accept it as a "generated type".

如果删除[<Generated>]属性,则会收到其他错误,提示我添加它.

If I remove the [<Generated>] attribute I get some other error telling me to add it.

这是否意味着类型提供程序将仅对动态发出的类型起作用(乍一看似乎很奇怪)?

Does this mean that type providers will only work on dynamically emitted types (which seems a weird requirement at first blush)?

此外,如果我这样做:

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

我收到一条错误消息,说应该是WW'1,但是返回了S'1.为什么返回的类型(由类型提供程序提供)必须与我在使用者中声明的类型名称匹配?

I get an error saying that WW'1 was expected but S'1 was returned. Why does the returned type (by the type provider) have to match the type name I declare in the consumer?

推荐答案

有关类型提供程序的一些重要事项.首先,提供了两种类型:

There are a few important things to realize about type providers. First of all, there are two kinds of provided types:

  1. 生成的类型是真正的.NET类型,它们嵌入到使用类型提供程序的程序集中(这是包装诸如sqlmetal之类的代码生成工具的类型提供程序所使用的类型)
  2. 擦除类型是模拟类型,在编译代码时由其他类型表示.
  1. Generated types are real .NET types that get embedded into the assembly that uses the type provider (this is what the type providers that wrap code generation tools like sqlmetal use)
  2. Erased types are simulated types which are represented by some other type when the code is compiled.

单挑,控制这种区别的机制仍然悬而未决.在预览中,需要在嵌入了生成类型的程序集中使用[<Generate>]属性,并且在使用提供的已擦除类型时,不应使用[<Generate>]属性.我相信(但不能确定暂时不会记住),在提供的一端,生成度是根据类型的Assembly属性确定的.

Just as a heads-up, the mechanisms for controlling this distinction are still somewhat up in the air. In the preview, you need to use the [<Generate>] attribute in the assembly into which generated types are being embedded, and you should not use the [<Generate>] attribute when using an erased provided type. I believe (but can't remember for sure off hand) that on the provided end generated-ness is determined based on the type's Assembly property.

此外,请记住,在实现API时,您不一定要使用实际类型(例如,通过typeof<X>)-您经常需要使用从System.Type派生的自定义类型.不同方法之间必须满足很多不变式.原始类型提供程序API并不易于使用-我建议等待发布一些使用更好的API包装器的示例(我希望该示例将在接下来的几周内发生).

Also, keep in mind that you don't necessarily want to use actual types (e.g. via typeof<X>) when implementing the API - you'll frequently want to use custom types derived from System.Type. There are a lot of invariants that must be satisfied among the different methods. The raw type provider API is not easy to use - I'd suggest waiting for some examples to be released which use a nicer API wrapper (which I hope should take place within the next few weeks).

话虽如此,从快速的角度来看,这里至少是您目前使用的方法中的一些对我来说是错误的:

Having said that, from a quick look here are at least a few things in your current approach which look wrong to me:

  1. 您从ApplyStaticArguments返回的类型与参数typeNameWithArguments的名称不同.大概这就是为什么在提及类型名称时会出错的原因.
  2. 您正在尝试使用类型缩写,以从非泛型类型(例如S<S<S<S<S<Z>>>>>)创建泛型类型(例如WW<'a>).
  1. The type that you're returning from ApplyStaticArguments doesn't have the same name as the argument typeNameWithArguments. Presumably this is why you're getting the error mentioning the type names.
  2. You're trying to use a type abbreviation which creates a generic type (e.g. WW<'a>) from a non-generic type (e.g. S<S<S<S<S<Z>>>>>).

这篇关于F#类型提供程序-“仅返回生成的类型"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆