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

查看:16
本文介绍了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.

提醒一下,控制这种区别的机制仍然有些悬而未决.在预览中,您需要在嵌入生成类型的程序集中使用 [] 属性,并且不应使用 [] 使用擦除的提供类型时的属性.我相信(但不能肯定地记住)在所提供的端生成性是根据类型的 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) - 您经常希望使用派生自的自定义类型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>>>>>).
  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天全站免登陆