简体   繁体   English

为什么我的“代码不够通用。类型变量 'a 无法泛化,因为它会超出其范围”?

[英]Why is my "code not sufficiently generic. The type variable 'a could not be generalized because it would escape its scope"?

Is there a way to get this generic function to work?有没有办法让这个通用的 function 工作?

module MarketData
open System.Collections.Generic

//start of mocks
type Name = Name of string with static member GetName = Name
type Element = 
    Element of string
    with
        member this.GetElementAsString x = ""
        member this.HasElement x = true
        member this.GetElement x = this
        member this.GetValueAsElement x = this
        member this.NumValues = 0

type MessageType = MessageType of string with member this.Equals s = this = MessageType s
type Msg = 
    {
        msg: string
        MessageType: MessageType
    }
    member this.HasElement x = true
    member this.GetElement x = Element ""

module Event =
    type EventType =
    |RESPONSE
    |PARTIAL_RESPONSE
    |SESSION_STATUS

type Event =
    {
        Messages: Msg seq
        Type: Event.EventType
    }
    interface IEnumerable<Msg> with
        member this.GetEnumerator () =
            this.Messages.GetEnumerator()

type Session =
    Session of string
    with
        member this.NextEvent() = {Messages = Seq.empty; Type = Event.EventType.RESPONSE}
// end of mocks


type FieldName = 
        FieldName of Name
    with 
        member this.AsName = let (FieldName x) = this in x
        static member FromString s = Name.GetName(s) |> FieldName

type SecurityName = SecurityName of string with member this.AsString = let (SecurityName x) = this in x

type ExtractState<'a> = 
    {
        Errors:string list
        Data:'a list
    }
    member this.ConsError e = {this with Errors = e::this.Errors}
    member this.ConsData x = {this with Data = x::this.Data}
    static member Empty = {Errors =[]; Data = []}

type RecordConstructor<'a> = SecurityName -> Element -> 'a
type SecurityProcessor<'a> = ExtractState<'a> -> Element -> ExtractState<'a>

module BbdData =
    [<RequireQualifiedAccess>]
    module Names =
        let SecurityData = Name.GetName("securityData")
        let Security = Name.GetName("security")
        let FieldData = Name.GetName("fieldData")
        let ResponseError = Name.GetName("responseError")
        let SecurityError = Name.GetName("securityError")
        let FieldExceptions = Name.GetName("fieldExceptions")
        let FieldId = Name.GetName("fieldId")
        let ErrorInfo = Name.GetName("errorInfo")
        let Category = Name.GetName("category")
        let Message = Name.GetName("message")

    let (|CompleteResponse|_|) (event:Event) =
        if event.Type = Event.EventType.RESPONSE then
            event |> Some
        else
            None

    let (|PartialResponse|_|) (event:Event) =
        if event.Type = Event.EventType.PARTIAL_RESPONSE then
            event |> Some
        else
            None 

    let (|SessionTerminated|_|) (event:Event) =
        if event.Type = Event.EventType.SESSION_STATUS then
            if event |> Seq.exists (fun m -> m.MessageType.Equals("SessionTerminated")) then
                Some ()
            else
                None
        else
            None
            

    //let sessionOptions = SessionOptions()
    //let session = new Session(sessionOptions)
    //session.Start() |> printfn "session open: %b" 
    //session.OpenService("//blp/refdata") |> printfn "service is open: %b"
    let session = Session ""

    let eventErrorMsg errorPrefix (elemError:Element) =
        let category = elemError.GetElementAsString(Names.Category)
        let msg = elemError.GetElementAsString(Names.Message)
        sprintf "%s -> %s -> %s" errorPrefix category msg

    let processRefSecurity<'a> (f:RecordConstructor<'a>) (state:ExtractState<'a>) (elemSecurity:Element) =
        let strSecurity = elemSecurity.GetElementAsString(Names.Security)
        if elemSecurity.HasElement(Names.SecurityError) then
            elemSecurity.GetElement(Names.SecurityError) |> eventErrorMsg strSecurity |> state.ConsError
        else
            elemSecurity.GetElement(Names.FieldData) |> f (SecurityName strSecurity) |> state.ConsData

    let processSecurities<'a> (securityData:Element) (f:SecurityProcessor<'a>) n initialState =
        let rec innerLoop iSec state =
            if iSec > n - 1 then
                state
            else
                securityData.GetValueAsElement(iSec) |> f state |> innerLoop (iSec - 1)
        innerLoop 0 initialState            

    let processResponseEvent<'a> (event:Event) f (state:ExtractState<'a>) =
        event |> Seq.fold (fun (innerState:ExtractState<'a>) msg ->
            if msg.HasElement(Names.ResponseError) then
                msg.GetElement(Names.ResponseError) |> eventErrorMsg "Request Failed" |> innerState.ConsError
            else
                let securityData = msg.GetElement(Names.SecurityData)
                let n = securityData.NumValues          
                processSecurities securityData f n innerState
        ) state

    let eventLoop f outerState =
        let rec innerLoop state =
            match session.NextEvent() with
            |PartialResponse event ->
                let newState = processResponseEvent event f state
                innerLoop newState
            |CompleteResponse event ->
                let newState = processResponseEvent event f state
                newState
            |SessionTerminated() ->
                failwith "session terminated"
            |_ -> innerLoop state
        innerLoop outerState        

    let sendRefRequest<'a> securities fields (f:RecordConstructor<'a>) =
        //let refDataService = session.GetService("//blp/refdata")
        //let request = refDataService.CreateRequest("ReferenceDataRequest")
        //let elemSecurities = request.GetElement("securities")
        //securities |> Seq.iter(fun (s:string) -> elemSecurities.AppendValue(s))
        //let elemFields = request.GetElement("fields")
        //fields |> Seq.iter(fun (s:string) -> elemFields.AppendValue(s))
        //session.SendRequest(request, null) |> ignore
        let secProcessor : SecurityProcessor<'a> = processRefSecurity f
        eventLoop secProcessor ExtractState<'a>.Empty

This is supposed to be a convenience wrapper around an API provided by Bloomberg.这应该是 Bloomberg 提供的 API 的便利包装。 The idea is that the user supplies a function that creates a record from an Element provided by Bloomberg.这个想法是用户提供一个 function 从彭博提供的Element创建记录。 The contents of the element depends on the specific fields requested.元素的内容取决于请求的特定字段。 The RecordConstructor<'a> takes extracts all those field values from the Element and makes 'a . RecordConstructor<'a>Element中提取所有这些字段值并生成'a

sendRefRequest is, according to the compiler, not sufficiently generic.根据编译器的说法, sendRefRequest不够通用。

It seems to me that the problem is here:在我看来,问题出在这里:

type ExtractState<'a> = 
    {
        Errors:string list
        Data:'a list
    }
    member this.ConsError e = {this with Errors = e::this.Errors}
    member this.ConsData x = {this with Data = x::this.Data}
    static member Empty = {Errors =[]; Data = []}

The last line doesn't constraint the empty list Data to be a list<'a> .最后一行不将空列表Data限制为list<'a>

If you add a type annotation somewhere to fix that, the error message will go away:如果您在某处添加类型注释来修复该问题,错误消息将消失 go:

static member Empty = {Errors =[]; Data = []}: ExtractState<'a>

BTW: this will take you to the next error:顺便说一句:这会将您带到下一个错误:

~vsFE66.fsx(36,19): error FS0366: No implementation was given for 'System.Collections.IEnumerable.GetEnumerator(): System.Collections.IEnumerator'. Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, eg 'interface... with member...'.

Just add: interface System.Collections.IEnumerable with member this.GetEnumerator () = this.Messages.GetEnumerator():> System.Collections.IEnumerator只需添加: interface System.Collections.IEnumerable with member this.GetEnumerator () = this.Messages.GetEnumerator():> System.Collections.IEnumerator

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 F#显式成员约束:无法广义化类型变量^ T,因为它将逃避其范围 - F# explicit member constraints: The type variable ^T could not be generalized because it would escape its scope F#通用问题:无法笼统,因为它将逃避其范围 - F# Generic Problem: could not be generalized because it would escape its scope 为什么“代码不够通用”? - Why 'Code is not sufficiently generic'? 将类型约束添加到派生类型F#(此代码不够通用) - Add type constraint to derived type F# (This code is not sufficiently generic) 为什么这段代码会抱怨“泛型类型定义的arity”? - Why would this code complain about “the arity of the generic type definition”? 可以容纳任意T类型的泛型类的变量类型是否存在任何基本缺陷? - Would there be any fundamental flaw in a variable type that could hold generic classes of arbitrary T types? 为什么不能扩展接口“泛型方法”并将其类型缩小到继承的接口“类通用”? - Why can't I extend an interface “generic method” and narrow its type to my inherited interface “class generic”? 为什么通用接口不能实现动态类型? - Why generic interface could not implement dynamic type? 为什么我得到“无法推断出通用参数”,通用类型 - why I am getting “generic parameter could not be inferred” , generic type TypeScript泛型类,它创建类型变量类的实例? - TypeScript generic class that creates instances of its type variable's class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM