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我模拟了各种类型。代码现在是自包含的,错误显示出来。不确定我为什么问这个问题做得这么差。对不起。