Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 为什么我的;代码不够通用。类型变量';a不能被广义化,因为它将超出其范围;?_Generics_F# - Fatal编程技术网

Generics 为什么我的;代码不够通用。类型变量';a不能被广义化,因为它将超出其范围;?

Generics 为什么我的;代码不够通用。类型变量';a不能被广义化,因为它将超出其范围;?,generics,f#,Generics,F#,有没有办法让这个通用函数正常工作 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 = ""

有没有办法让这个通用函数正常工作

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
模块市场数据
open System.Collections.Generic
//模拟的开始
type Name=具有静态成员GetName=Name的字符串的名称
类型元素=
字符串元素
具有
成员this.GetElementAsString x=“”
成员this.HasElement x=true
成员this.GetElement x=this
成员this.GetValueAsElement x=此
成员this.NumValues=0
type MessageType=MessageType包含成员this的字符串。等于s=this=MessageType s
类型Msg=
{
msg:string
MessageType:MessageType
}
成员this.HasElement x=true
成员this.GetElement x=元素“”
模块事件=
类型EventType=
|回应
|部分反应
|会话状态
类型事件=
{
信息:Msg seq
类型:Event.EventType
}
接口IEnumerable with
成员this.GetEnumerator()=
this.Messages.GetEnumerator()
类型会话=
字符串会话
具有
成员this.NextEvent()={Messages=Seq.empty;Type=Event.EventType.RESPONSE}
//模拟结束
类型字段名=
名称的字段名
具有
成员this.AsName=let(FieldName x)=x中的this
静态成员FromString s=Name.GetName|>FieldName
键入SecurityName=SecurityName,该字符串的成员为this.AsString=let(SecurityName x)=x中的this
键入ExtractState->Element->ExtractState(f:RecordConstructor)(elemSecurity:Element)=
设strSecurity=elemSecurity.GetElementAsString(Names.Security)
如果elemSecurity.HasElement(Names.SecurityError),则
elemSecurity.GetElement(Names.SecurityError)|>eventErrorMsg strSecurity |>state.ConsError
其他的
elemSecurity.GetElement(Names.FieldData)|>f(SecurityName strSecurity)|>state.ConsData
让我们来看看(n)initialState=
让rec innerLoop iSec状态=
如果iSec>n-1,则
状态
其他的
securityData.GetValueAsElement(iSec)|>f state |>innerLoop(iSec-1)
innerLoop 0初始状态
让processResponseEvent)=
事件|>Seq.fold(fun)(innerState:ExtractState安全字段(f:RecordConstructor=processRefSecurity)
eventLoop secProcessor ExtractState
元素
提取所有这些字段值,并生成
'a


根据编译器的说法,
sendRefRequest
不够通用。

在我看来,问题在于:

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 = []}
键入ExtractState

如果在某个位置添加类型批注以修复此问题,则错误消息将消失:


static member Empty={Errors=[];Data=[]:ExtractState确切的编译器错误是什么?此代码不够泛型。无法泛化类型变量“a”,因为它将超出其作用域。我认为您需要提供足够完整的代码来显示错误-我尝试添加缺少的部分,但不知道这在您的代码库中实际是什么样子(至少是
processRefSecurity
eventLoop
的类型定义)没有足够的信息来说明问题所在。模拟dll函数可以让我们的生活更轻松。越简单,得到正确答案的机会就越多。@Gus我模拟了各种类型。代码现在是自包含的,错误显示出来。不确定我为什么问这个问题做得这么差。对不起。